Skip to content

Commit 41c491c

Browse files
feat: added columns per row, vertical and horizonal spacing option
1 parent 70561a0 commit 41c491c

File tree

10 files changed

+141
-58
lines changed

10 files changed

+141
-58
lines changed
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading

client/packages/lowcoder-design/src/icons/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,3 +291,5 @@ export { ReactComponent as TimeLineIcon } from "icons/icon-timeline-comp.svg"
291291
export { ReactComponent as LottieIcon } from "icons/icon-lottie.svg";
292292
export { ReactComponent as MentionIcon } from "icons/icon-mention-comp.svg";
293293
export { ReactComponent as AutoCompleteCompIcon } from "icons/icon-autocomplete-comp.svg";
294+
export { ReactComponent as WidthIcon } from "icons/icon-width.svg";
295+
export { ReactComponent as ResponsiveLayoutCompIcon } from "icons/icon-responsive-layout-comp.svg";

client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx

Lines changed: 67 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Row } from "antd";
1+
import { Row, Col } from "antd";
22
import { JSONObject, JSONValue } from "util/jsonTypes";
33
import { CompAction, CompActionTypes, deleteCompAction, wrapChildAction } from "lowcoder-core";
44
import { DispatchType, RecordConstructorToView, wrapDispatch } from "lowcoder-core";
@@ -30,26 +30,29 @@ import { EditorContext } from "comps/editorState";
3030
import { checkIsMobile } from "util/commonUtils";
3131
import { messageInstance } from "lowcoder-design";
3232
import { BoolControl } from "comps/controls/boolControl";
33+
import { NumberControl } from "comps/controls/codeControl";
3334

3435
const RowWrapper = styled(Row)<{$style: ResponsiveLayoutRowStyleType}>`
3536
height: 100%;
3637
border: 1px solid ${(props) => props.$style.border};
3738
border-radius: ${(props) => props.$style.radius};
3839
padding: ${(props) => props.$style.padding};
3940
background-color: ${(props) => props.$style.background};
41+
overflow-x: auto;
4042
`;
4143

42-
const ColWrapper = styled(InnerGrid)<{
44+
const ColWrapper = styled(Col)<{
4345
$style: ResponsiveLayoutColStyleType,
44-
$minWidth: string,
46+
$minWidth?: string,
47+
$backgroundImage?: string,
4548
}>`
4649
height: 100%;
4750
min-width: ${(props) => props.$minWidth};
48-
border: 1px solid ${(props) => props.$style.border};
49-
border-radius: ${(props) => props.$style.radius};
50-
padding: ${(props) => props.$style.padding};
51-
background-color: ${(props) => props.$style.background};
52-
flex: 1 1 auto;
51+
52+
> div {
53+
background: ${(props) => `center / cover url(${props.$backgroundImage}) no-repeat, ${props.$style.background} !important`};
54+
border: 1px solid ${(props) => props.$style.border} !important;
55+
}
5356
`;
5457

5558
const childrenMap = {
@@ -61,31 +64,28 @@ const childrenMap = {
6164
}),
6265
autoHeight: AutoHeightControl,
6366
rowBreak: withDefault(BoolControl, false),
64-
rowStyle: withDefault(styleControl(ResponsiveLayoutRowStyle), {
65-
background: 'transparent',
66-
border: 'transparent',
67-
margin: '0',
68-
padding: '0',
69-
}),
70-
columnStyle: styleControl(ResponsiveLayoutColStyle),
67+
rowStyle: withDefault(styleControl(ResponsiveLayoutRowStyle), {}),
68+
columnStyle: withDefault(styleControl(ResponsiveLayoutColStyle), {}),
69+
columnPerRowLG: withDefault(NumberControl, 4),
70+
columnPerRowMD: withDefault(NumberControl, 2),
71+
columnPerRowSM: withDefault(NumberControl, 1),
72+
verticalSpacing: withDefault(NumberControl, 8),
73+
horizontalSpacing: withDefault(NumberControl, 8),
7174
};
7275

7376
type ViewProps = RecordConstructorToView<typeof childrenMap>;
7477
type ResponsiveLayoutProps = ViewProps & { dispatch: DispatchType };
7578
type ColumnContainerProps = Omit<ContainerBaseProps, 'style'> & {
7679
style: ResponsiveLayoutColStyleType
77-
minWidth: string,
7880
}
7981

8082
const ColumnContainer = (props: ColumnContainerProps) => {
8183
return (
82-
<ColWrapper
84+
<InnerGrid
8385
{...props}
8486
emptyRows={15}
85-
bgColor={"white"}
8687
hintPlaceholder={HintPlaceHolder}
87-
$style={props.style}
88-
$minWidth={props.minWidth}
88+
style={props.style}
8989
/>
9090
);
9191
};
@@ -99,8 +99,12 @@ const ResponsiveLayout = (props: ResponsiveLayoutProps) => {
9999
rowBreak,
100100
rowStyle,
101101
columnStyle,
102+
columnPerRowLG,
103+
columnPerRowMD,
104+
columnPerRowSM,
105+
verticalSpacing,
106+
horizontalSpacing,
102107
} = props;
103-
console.log(props)
104108

105109
const editorState = useContext(EditorContext);
106110
const maxWidth = editorState.getAppSettings().maxWidth;
@@ -112,31 +116,43 @@ const ResponsiveLayout = (props: ResponsiveLayoutProps) => {
112116
<RowWrapper
113117
$style={rowStyle}
114118
wrap={rowBreak}
119+
gutter={[horizontalSpacing, verticalSpacing]}
115120
>
116121
{columns.map(column => {
117122
const id = String(column.id);
118123
const childDispatch = wrapDispatch(wrapDispatch(dispatch, "containers"), id);
119124
if(!containers[id]) return null
120125
const containerProps = containers[id].children;
126+
121127
const columnCustomStyle = {
122128
margin: !_.isEmpty(column.margin) ? column.margin : columnStyle.margin,
123129
padding: !_.isEmpty(column.padding) ? column.padding : columnStyle.padding,
124-
border: !_.isEmpty(column.border) ? column.border : columnStyle.border,
125130
radius: !_.isEmpty(column.radius) ? column.radius : columnStyle.radius,
131+
border: !_.isEmpty(column.border) ? column.border : columnStyle.border,
126132
background: !_.isEmpty(column.background) ? column.background : columnStyle.background,
127133
}
128-
console.log(column);
134+
const noOfColumns = columns.length;
129135
return (
130-
<ColumnContainer
136+
<ColWrapper
131137
key={id}
132-
layout={containerProps.layout.getView()}
133-
items={gridItemCompToGridItems(containerProps.items.getView())}
134-
positionParams={containerProps.positionParams.getView()}
135-
dispatch={childDispatch}
136-
autoHeight={props.autoHeight}
137-
style={columnCustomStyle}
138-
minWidth={column.minWidth}
139-
/>
138+
lg={24/(noOfColumns < columnPerRowLG ? noOfColumns : columnPerRowLG)}
139+
md={24/(noOfColumns < columnPerRowMD ? noOfColumns : columnPerRowMD)}
140+
sm={24/(noOfColumns < columnPerRowSM ? noOfColumns : columnPerRowSM)}
141+
$style={columnCustomStyle}
142+
$minWidth={column.minWidth}
143+
$backgroundImage={
144+
!_.isEmpty(column.backgroundImage) && column.backgroundImage
145+
}
146+
>
147+
<ColumnContainer
148+
layout={containerProps.layout.getView()}
149+
items={gridItemCompToGridItems(containerProps.items.getView())}
150+
positionParams={containerProps.positionParams.getView()}
151+
dispatch={childDispatch}
152+
autoHeight={props.autoHeight}
153+
style={columnCustomStyle}
154+
/>
155+
</ColWrapper>
140156
)
141157
})
142158
}
@@ -166,6 +182,25 @@ export const ResponsiveLayoutBaseComp = (function () {
166182
label: trans("responsiveLayout.rowBreak")
167183
})}
168184
</Section>
185+
<Section name={trans("responsiveLayout.columnsPerRow")}>
186+
{children.columnPerRowLG.propertyView({
187+
label: trans("responsiveLayout.desktop")
188+
})}
189+
{children.columnPerRowMD.propertyView({
190+
label: trans("responsiveLayout.tablet")
191+
})}
192+
{children.columnPerRowSM.propertyView({
193+
label: trans("responsiveLayout.mobile")
194+
})}
195+
</Section>
196+
<Section name={trans("responsiveLayout.columnsSpacing")}>
197+
{children.horizontalSpacing.propertyView({
198+
label: trans("responsiveLayout.horizontal")
199+
})}
200+
{children.verticalSpacing.propertyView({
201+
label: trans("responsiveLayout.vertical")
202+
})}
203+
</Section>
169204
<Section name={trans("responsiveLayout.rowStyle")}>
170205
{children.rowStyle.getPropertyView()}
171206
</Section>

client/packages/lowcoder/src/comps/comps/tabs/tabbedContainerComp.tsx

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -196,20 +196,6 @@ const TabbedContainer = (props: TabbedContainerProps) => {
196196
</BackgroundColorContext.Provider>
197197
)
198198
}
199-
// return (
200-
// <TabPane tab={label} key={tab.key} forceRender>
201-
// <BackgroundColorContext.Provider value={props.style.background}>
202-
// <ContainerInTab
203-
// layout={containerProps.layout.getView()}
204-
// items={gridItemCompToGridItems(containerProps.items.getView())}
205-
// positionParams={containerProps.positionParams.getView()}
206-
// dispatch={childDispatch}
207-
// autoHeight={props.autoHeight}
208-
// containerPadding={[paddingWidth, 20]}
209-
// />
210-
// </BackgroundColorContext.Provider>
211-
// </TabPane>
212-
// );
213199
})
214200

215201
return (

client/packages/lowcoder/src/comps/controls/optionsControl.tsx

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,24 @@ import {
2020
MultiBaseComp,
2121
withFunction,
2222
} from "lowcoder-core";
23-
import { AutoArea, controlItem, Option } from "lowcoder-design";
23+
import {
24+
AutoArea,
25+
CompressIcon,
26+
controlItem,
27+
ExpandIcon,
28+
IconRadius,
29+
Option,
30+
WidthIcon,
31+
ImageCompIcon,
32+
} from "lowcoder-design";
2433
import styled from "styled-components";
2534
import { lastValueIfEqual } from "util/objectUtils";
2635
import { getNextEntityName } from "util/stringUtils";
2736
import { JSONValue } from "util/jsonTypes";
2837
import { ButtonEventHandlerControl } from "./eventHandlerControl";
2938
import { ControlItemCompBuilder } from "comps/generators/controlCompBuilder";
3039
import { ColorControl } from "./colorControl";
40+
import { StringStateControl } from "./codeStateControl";
3141

3242
const OptionTypes = [
3343
{
@@ -523,13 +533,44 @@ export const TabsOptionControl = manualOptionsControl(TabsOption, {
523533
autoIncField: "id",
524534
});
525535

536+
const StyledIcon = styled.span`
537+
margin: 0 4px 0 14px;
538+
`;
539+
540+
const StyledContent = styled.div`
541+
> div {
542+
margin: 4px 0;
543+
flex-direction: row;
544+
gap: 4px 0px;
545+
flex-wrap: wrap;
546+
547+
> div:nth-of-type(1) {
548+
flex: 0 0 96px;
549+
550+
div {
551+
line-height: 16px;
552+
}
553+
}
554+
555+
> svg {
556+
height: 30px;
557+
width: 25px;
558+
}
559+
560+
> div:nth-of-type(2) {
561+
flex: 1 1 auto;
562+
}
563+
}
564+
`;
565+
526566
const ColumnOption = new MultiCompBuilder(
527567
{
528568
id: valueComp<number>(-1),
529569
label: StringControl,
530570
key: StringControl,
531571
minWidth: withDefault(RadiusControl, ""),
532572
background: withDefault(ColorControl, ""),
573+
backgroundImage: withDefault(StringControl, ""),
533574
border: withDefault(ColorControl, ""),
534575
radius: withDefault(RadiusControl, ""),
535576
margin: withDefault(StringControl, ""),
@@ -538,26 +579,39 @@ const ColumnOption = new MultiCompBuilder(
538579
(props) => props
539580
)
540581
.setPropertyViewFn((children) => (
541-
<>
582+
<StyledContent>
542583
{children.minWidth.propertyView({
543-
label: trans('responsiveLayout.minWidth')
584+
label: trans('responsiveLayout.minWidth'),
585+
preInputNode: <StyledIcon as={WidthIcon} title="" />,
586+
placeholder: '3px',
544587
})}
545588
{children.background.propertyView({
546-
label: trans('style.background')
589+
label: trans('style.background'),
590+
})}
591+
{children.backgroundImage.propertyView({
592+
label: `Background Image`,
593+
// preInputNode: <StyledIcon as={ImageCompIcon} title="" />,
594+
placeholder: 'https://temp.im/350x400',
547595
})}
548596
{children.border.propertyView({
549597
label: trans('style.border')
550598
})}
551599
{children.radius.propertyView({
552-
label: trans('style.borderRadius')
600+
label: trans('style.borderRadius'),
601+
preInputNode: <StyledIcon as={IconRadius} title="" />,
602+
placeholder: '3px',
553603
})}
554604
{children.margin.propertyView({
555-
label: trans('style.margin')
605+
label: trans('style.margin'),
606+
preInputNode: <StyledIcon as={ExpandIcon} title="" />,
607+
placeholder: '3px',
556608
})}
557609
{children.padding.propertyView({
558-
label: trans('style.padding')
610+
label: trans('style.padding'),
611+
preInputNode: <StyledIcon as={CompressIcon} title="" />,
612+
placeholder: '3px',
559613
})}
560-
</>
614+
</StyledContent>
561615
))
562616
.build();
563617

client/packages/lowcoder/src/comps/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ import {
9696
LottieIcon,
9797
MentionIcon,
9898
AutoCompleteCompIcon,
99+
ResponsiveLayoutCompIcon,
99100
} from "lowcoder-design";
100101

101102
import { defaultFormData, FormComp } from "./comps/formComp/formComp";
@@ -887,7 +888,7 @@ const uiCompMap: Registry = {
887888
enName: "Responsive Layout",
888889
description: trans("uiComp.responsiveLayoutCompDesc"),
889890
categories: ["container", "common"],
890-
icon: TabbedContainerCompIcon,
891+
icon: ResponsiveLayoutCompIcon,
891892
keywords: trans("uiComp.responsiveLayoutCompKeywords"),
892893
comp: ResponsiveLayoutComp,
893894
withoutLoading: true,

client/packages/lowcoder/src/i18n/locales/en.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2512,6 +2512,7 @@ export const en = {
25122512
responsiveLayout: {
25132513
column: "Columns",
25142514
atLeastOneColumnError: "Responsive layout keeps at least one Column",
2515+
columnsPerRow: "Columns per Row",
25152516
columnsSpacing: "Columns Spacing(px)",
25162517
horizontal: "Horizontal",
25172518
vertical: "Vertical",
@@ -2520,7 +2521,7 @@ export const en = {
25202521
desktop: "Desktop",
25212522
rowStyle: "Row Style",
25222523
columnStyle: "Column Style",
2523-
minWidth: "Minimum Width",
2524+
minWidth: "Min. Width",
25242525
rowBreak: "Row Break",
25252526
},
25262527
};

client/packages/lowcoder/src/i18n/locales/zh.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2502,6 +2502,7 @@ timeLine: {
25022502
responsiveLayout: {
25032503
column: "列",
25042504
atLeastOneColumnError: "响应式布局至少保留一列",
2505+
columnsPerRow: "每行列数",
25052506
columnsSpacing: "列间距(px)",
25062507
horizontal: "水平的",
25072508
vertical: "垂直的",
@@ -2510,7 +2511,7 @@ timeLine: {
25102511
desktop: "桌面",
25112512
rowStyle: "行式",
25122513
columnStyle: "栏目样式",
2513-
minWidth: "最小宽度",
2514+
minWidth: "分钟。宽度",
25142515
rowBreak: "断行",
25152516
}
25162517
};

client/packages/lowcoder/src/pages/editor/editorConstants.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
TimeLineIcon,
4040
MentionIcon,
4141
AutoCompleteCompIcon,
42+
ResponsiveLayoutCompIcon,
4243
} from "lowcoder-design";
4344

4445
export const CompStateIcon: {
@@ -107,5 +108,5 @@ export const CompStateIcon: {
107108
timeline: <TimeLineIcon />,
108109
mention: <MentionIcon/>,
109110
autocomplete: <AutoCompleteCompIcon />,
110-
responsiveLayout: <LeftContainer />,
111+
responsiveLayout: <ResponsiveLayoutCompIcon />,
111112
};

0 commit comments

Comments
 (0)