Skip to content

Commit a73e727

Browse files
Merge pull request #572 from SoftwareBrothers/beta
Beta
2 parents 2c991d3 + 6135030 commit a73e727

File tree

9 files changed

+162
-146
lines changed

9 files changed

+162
-146
lines changed

docs/ layout1.png

-47 KB
Binary file not shown.

docs/layout2.png

-47.3 KB
Binary file not shown.

docs/layout3.png

-56.6 KB
Binary file not shown.

docs/layout4.png

-52.6 KB
Binary file not shown.

docs/layout5.png

-52.9 KB
Binary file not shown.

index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export { flatten, unflatten } from './types/src/admin-bro'
88
export * from '@admin-bro/design-system'
99
export * from './types/src/frontend/store/store'
1010
export * from './types/src/backend/utils/build-feature'
11+
export * from './types/src/backend/utils/layout-element-parser'
1112
export * from './types/src/frontend/utils/overridable-component'
1213

1314
export { default as Router } from './types/src/backend/router'

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "admin-bro",
3-
"version": "3.1.2",
3+
"version": "3.2.0",
44
"description": "Admin panel for apps written in node.js",
55
"main": "index.js",
66
"types": "index.d.ts",

src/backend/actions/action.interface.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import ViewHelpers from '../utils/view-helpers'
44
import BaseRecord from '../adapters/base-record'
55
import BaseResource from '../adapters/base-resource'
66
import ActionDecorator from '../decorators/action-decorator'
7-
import { LayoutElement } from '../utils/layout-element-parser'
7+
import { LayoutElement, LayoutElementFunction } from '../utils/layout-element-parser'
88
import RecordJSON from '../decorators/record-json.interface'
99
import { NoticeMessage } from '../../frontend/store/with-notice'
1010
import { TranslateFunctions } from '../../utils/translate-functions.factory'
@@ -583,6 +583,7 @@ export default interface Action <T extends ActionResponse> {
583583
*
584584
* This is an example of defining a layout
585585
*
586+
* ```
586587
* const layout = [{ width: 1 / 2 }, [
587588
* ['@H3', { children: 'Company data' }],
588589
* 'companyName',
@@ -596,13 +597,16 @@ export default interface Action <T extends ActionResponse> {
596597
* ]],
597598
* ],
598599
* ]
600+
* ```
599601
*
600-
* Alternatively you can pass a function taking {@link CurrentAdmin} as an argument.
601-
* This will allow you to show/hide given property for restricted users.
602+
* Alternatively you can pass a {@link LayoutElementFunction function} taking
603+
* {@link CurrentAdmin} as an argument. This will allow you to show/hide
604+
* given property for restricted users.
602605
*
603606
* To see entire documentation and more examples visit {@link LayoutElement}
604607
*
605608
* @see LayoutElement
609+
* @see LayoutElementFunction
606610
*/
607-
layout?: ((currentAdmin?: CurrentAdmin) => Array<LayoutElement>) | Array<LayoutElement>;
611+
layout?: LayoutElementFunction | Array<LayoutElement>;
608612
}
+152-141
Original file line numberDiff line numberDiff line change
@@ -1,148 +1,8 @@
11
/* eslint-disable max-len */
22
import { BoxProps, HeaderProps, TextProps, BadgeProps, ButtonProps, LinkProps, LabelProps, IconProps } from '@admin-bro/design-system'
33
import { PropsWithChildren } from 'react'
4+
import { CurrentAdmin } from '../../current-admin.interface'
45

5-
/**
6-
* @typedef {String | Array} LayoutElement
7-
*
8-
* @description
9-
* {@link LayoutElement} is used to change the default layout of edit and show {@link Action actions}.
10-
* You define the layout as an {@link Array<LayoutElement>} and AdminBro renders it with React components.
11-
*
12-
* You don't have to know React to create usable Layout for you actions but be sure
13-
* to take a look at the possible **Props** which can be used to style the components.
14-
* The most often used props are {@link BoxProps}, because {@link Box} is the default wrapper.
15-
*
16-
* ### Available values for a {@link LayoutElement} type
17-
*
18-
* To {@link Action#layout } you have to pass an {@link Array<LayoutElement>}. Where each
19-
* {@link LayoutElement} could have a different type defining its position and purpose.
20-
*
21-
* ### Type definition
22-
*
23-
* Those are available types of
24-
*
25-
* | Type | Purpose | Example |
26-
* |---------------|--------------------------------------------------------------|------------------|
27-
* | string | It will be changed to the property in vertical layout | `layout: ['name']` |
28-
* | Array<string> | It will be changed to the properties in vertical layout | `layout: [['name', 'surname']]` |
29-
* | [string, {@link BoxProps}] | property wrapped by {@link Box} component with {@link BoxProps} | `layout: [['name', {width: 1/2}]]` |
30-
* | [{@link BoxProps}, Array<LayoutElement>] | Creates a Box and nest all the child LayoutElements inside. | `layout: [[{width: 1/2}, ['name', 'surname']]]` |
31-
* | Array<LayoutElement> | For grouping LayoutElements inside a wrapper | `layout: [['name', {mt: 'xl'}], ['surname', , {ml: 'xl'}]]` |
32-
* | [@ComponentName, PropsWithChildren<ComponentProps>] | if you precede first item with "@" it will create component of this name | `layout: [['@Header', {children: 'User Data'}]]` |
33-
*
34-
* ### Examples
35-
*
36-
* Let say you have following properties in your database: `companyName`, `email`, `address` and `companySize`
37-
*
38-
* 1. The simplest horizontal layout:
39-
*
40-
* ```
41-
* const layout = [
42-
* 'companyName',
43-
* 'email',
44-
* 'address',
45-
* 'companySize',
46-
* ]
47-
* ```
48-
*
49-
* generates:
50-
*
51-
* <img src='./docs/layout1.png'>
52-
*
53-
* 2. Now Wrap everything with a {@link Box} of `2/3` max width and horizontal margin (mx)
54-
* set to auto. This will center all inputs
55-
*
56-
* ```
57-
* const layout = [
58-
* [{ width: 2 / 3, mx: 'auto' }, [
59-
* 'companyName',
60-
* 'email',
61-
* 'address',
62-
* 'companySize',
63-
* ]],
64-
* ]
65-
* ```
66-
*
67-
* > Hint: you can also pass an array to define how it will behave in a different responsive breakpoints.
68-
*
69-
* generates:
70-
*
71-
* <img src='./docs/layout2.png'>
72-
*
73-
* 3. Add headers between sections
74-
*
75-
* ```
76-
* const layout = [
77-
* [{ width: 2 / 3, mx: 'auto' }, [
78-
* ['@H3', { children: 'Company data' }],
79-
* 'companyName',
80-
* 'companySize',
81-
* ['@H3', { children: 'Contact Info' }],
82-
* 'email',
83-
* 'address',
84-
* ]],
85-
* ]
86-
* ```
87-
*
88-
* > To inject content inside the given Component pass children props to it.
89-
*
90-
* generates:
91-
*
92-
* <img src='./docs/layout3.png'>
93-
*
94-
* 4. Make email and address 50% width
95-
*
96-
* > We will wrap them with a Box (default component) which is a flex. Then we will have to wrap also each of them
97-
* with extra box to define paddings.
98-
*
99-
* I will also align to left top section that by removing `{ mx: auto }` and changing width to `1 / 2`.
100-
*
101-
* const layout = [{ width: 1 / 2 }, [
102-
* ['@H3', { children: 'Company data' }],
103-
* 'companyName',
104-
* 'companySize',
105-
* ]],
106-
* [
107-
* ['@H3', { children: 'Contact Info' }],
108-
* [{ flexDirection: 'row', flex: true }, [
109-
* ['email', { pr: 'default', flexGrow: 1 }],
110-
* ['address', { flexGrow: 1 }],
111-
* ]],
112-
* ],
113-
* ]
114-
*
115-
* generates:
116-
*
117-
* <img src='./docs/layout4.png'>
118-
*
119-
* 5. Lastly, take a look at the example with a function instead of {@link LayoutElement}.
120-
*
121-
* ```
122-
* const layout = currentAdmin => ([
123-
* ['@MessageBox', {
124-
* message: `Welcome ${currentAdmin && currentAdmin.email}`,
125-
* children: 'On this page yo can do whatever you like',
126-
* variant: 'info',
127-
* mb: 'xxl',
128-
* }],
129-
* [
130-
* 'companyName',
131-
* 'companySize',
132-
* 'email',
133-
* 'address',
134-
* ],
135-
* ])
136-
* ```
137-
*
138-
* * generates following Show page:
139-
*
140-
* <img src='./docs/layout5.png'>
141-
*
142-
* @memberof Action
143-
*/
144-
145-
// spacer for jsdoc
1466
export type LayoutElement =
1477
string |
1488
Array<string> |
@@ -163,6 +23,15 @@ export type LayoutElement =
16323
['@Icon', PropsWithChildren<IconProps>] |
16424
[string, PropsWithChildren<any>]
16525

26+
/**
27+
* Function returning Array<LayoutElement> used by {@link Action#layout}
28+
*
29+
* @return {Array<LayoutElement>}
30+
* @memberof Action
31+
* @alias LayoutElementFunction
32+
*/
33+
export type LayoutElementFunction = (currentAdmin?: CurrentAdmin) => Array<LayoutElement>
34+
16635
/**
16736
* It is generated from {@link Array<LayoutElement>} passed in {@link Action#layout}
16837
*
@@ -268,3 +137,145 @@ const layoutElementParser = (layoutElement: LayoutElement): ParsedLayoutElement
268137
}
269138

270139
export default layoutElementParser
140+
141+
142+
/**
143+
* {@link LayoutElement} is used to change the default layout of edit and show {@link Action actions}.
144+
* You define the layout as an {@link Array<LayoutElement>} and AdminBro renders it with React components.
145+
*
146+
* You don't have to know React to create usable Layout for you actions but be sure
147+
* to take a look at the possible **Props** which can be used to style the components.
148+
* The most often used props are {@link BoxProps}, because {@link Box} is the default wrapper.
149+
*
150+
* ### Available values for a {@link LayoutElement} type
151+
*
152+
* To {@link Action#layout } you have to pass an {@link Array<LayoutElement>}. Where each
153+
* {@link LayoutElement} could have a different type defining its position and purpose.
154+
*
155+
* ### Type definition
156+
*
157+
* Those are available types for {@link LayoutElement}
158+
*
159+
* | Type | Purpose | Example |
160+
* |---------------|--------------------------------------------------------------|------------------|
161+
* | string | It will be changed to the property in vertical layout | `layout: ['name']` |
162+
* | {@link Array<string>} | It will be changed to the properties in vertical layout | `layout: [['name', 'surname']]` |
163+
* | [string, {@link BoxProps}] | property wrapped by {@link Box} component with {@link BoxProps} | `layout: [['name', {width: 1/2}]]` |
164+
* | [{@link BoxProps}, {@link Array<LayoutElement>}] | Creates a Box and nest all the child LayoutElements inside. | `layout: [[{width: 1/2}, ['name', 'surname']]]` |
165+
* | {@link Array<LayoutElement>} | For grouping LayoutElements inside a wrapper | `layout: [['name', {mt: 'xl'}], ['surname', , {ml: 'xl'}]]` |
166+
* | [@ComponentName, PropsWithChildren<ComponentProps>] | if you precede first item with "@" it will create component of this name | `layout: [['@Header', {children: 'User Data'}]]` |
167+
*
168+
* ### Examples
169+
*
170+
* Let say you have following properties in your database: `companyName`, `email`, `address` and `companySize`
171+
*
172+
* #### 1. The simplest horizontal layout:
173+
*
174+
* ```
175+
* const layout = [
176+
* 'companyName',
177+
* 'email',
178+
* 'address',
179+
* 'companySize',
180+
* ]
181+
* ```
182+
*
183+
* generates:
184+
*
185+
* <img src='./images/layout1.png' style="margin-bottom: 20px">
186+
*
187+
* #### 2. Now Wrap everything with a {@link Box} of `2/3` max width and horizontal margin (mx) set to auto. This will center all inputs
188+
*
189+
* ```
190+
* const layout = [
191+
* [{ width: 2 / 3, mx: 'auto' }, [
192+
* 'companyName',
193+
* 'email',
194+
* 'address',
195+
* 'companySize',
196+
* ]],
197+
* ]
198+
* ```
199+
*
200+
* generates:
201+
*
202+
* <img src='./images/layout2.png'>
203+
*
204+
* > Hint: you can also pass an array to `width` to define how it will behave in a different responsive breakpoints.
205+
*
206+
* #### 3. Add headers between sections
207+
*
208+
* ```
209+
* const layout = [
210+
* [{ width: 2 / 3, mx: 'auto' }, [
211+
* ['@H3', { children: 'Company data' }],
212+
* 'companyName',
213+
* 'companySize',
214+
* ['@H3', { children: 'Contact Info' }],
215+
* 'email',
216+
* 'address',
217+
* ]],
218+
* ]
219+
* ```
220+
*
221+
* generates:
222+
*
223+
* <img src='./images/layout3.png' style="margin-bottom: 20px" >
224+
*
225+
* > To inject content inside the given Component pass children props to it.
226+
*
227+
* #### 4. Make email and address 50% width
228+
*
229+
* We will wrap them with a {@link Box} (default component) which is a flex.
230+
* Then we will have to wrap also each of them with extra box to define paddings.
231+
*
232+
* I will also align to left top section that by removing `{ mx: auto }` and changing width to `1 / 2`.
233+
*
234+
* ```
235+
* const layout = [{ width: 1 / 2 }, [
236+
* ['@H3', { children: 'Company data' }],
237+
* 'companyName',
238+
* 'companySize',
239+
* ]],
240+
* [
241+
* ['@H3', { children: 'Contact Info' }],
242+
* [{ flexDirection: 'row', flex: true }, [
243+
* ['email', { pr: 'default', flexGrow: 1 }],
244+
* ['address', { flexGrow: 1 }],
245+
* ]],
246+
* ],
247+
* ]
248+
* ```
249+
*
250+
* generates:
251+
*
252+
* <img src='./images/layout4.png' style="margin-bottom: 20px">
253+
*
254+
* #### 5. Lastly, take a look at the example with a function instead of {@link LayoutElement}.
255+
*
256+
* ```
257+
* const layout = currentAdmin => ([
258+
* ['@MessageBox', {
259+
* message: `Welcome ${currentAdmin && currentAdmin.email}`,
260+
* children: 'On this page yo can do whatever you like',
261+
* variant: 'info',
262+
* mb: 'xxl',
263+
* }],
264+
* [
265+
* 'companyName',
266+
* 'companySize',
267+
* 'email',
268+
* 'address',
269+
* ],
270+
* ])
271+
* ```
272+
*
273+
* Generates following **Show** page:
274+
*
275+
* <img src='./images/layout5.png'>
276+
*
277+
* @name LayoutElement
278+
* @typedef {String | Array} LayoutElement
279+
* @memberof Action
280+
* @alias LayoutElement
281+
*/

0 commit comments

Comments
 (0)