From 9d2d0431d9fc610ac64394086067081a3aecdb5c Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Fri, 18 Aug 2023 19:26:01 +0500 Subject: [PATCH 1/8] feat: added responsive layout component --- .../comps/comps/responsiveLayout/index.tsx | 1 + .../responsiveLayout/responsiveLayout.tsx | 282 ++++++++++++++++++ .../src/comps/controls/optionsControl.tsx | 51 +++- .../comps/controls/styleControlConstants.tsx | 14 + client/packages/lowcoder/src/comps/index.tsx | 16 + .../lowcoder/src/comps/uiCompRegistry.ts | 1 + .../packages/lowcoder/src/i18n/locales/en.ts | 18 ++ .../packages/lowcoder/src/i18n/locales/zh.ts | 18 ++ .../src/pages/editor/editorConstants.tsx | 1 + .../lowcoder/src/pages/editor/editorView.tsx | 1 - 10 files changed, 401 insertions(+), 2 deletions(-) create mode 100644 client/packages/lowcoder/src/comps/comps/responsiveLayout/index.tsx create mode 100644 client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx diff --git a/client/packages/lowcoder/src/comps/comps/responsiveLayout/index.tsx b/client/packages/lowcoder/src/comps/comps/responsiveLayout/index.tsx new file mode 100644 index 000000000..668003a69 --- /dev/null +++ b/client/packages/lowcoder/src/comps/comps/responsiveLayout/index.tsx @@ -0,0 +1 @@ +export { ResponsiveLayoutComp } from "./responsiveLayout"; diff --git a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx new file mode 100644 index 000000000..cd230fb5e --- /dev/null +++ b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx @@ -0,0 +1,282 @@ +import { Row } from "antd"; +import { JSONObject, JSONValue } from "util/jsonTypes"; +import { CompAction, CompActionTypes, deleteCompAction, wrapChildAction } from "lowcoder-core"; +import { DispatchType, RecordConstructorToView, wrapDispatch } from "lowcoder-core"; +import { AutoHeightControl } from "comps/controls/autoHeightControl"; +import { stringExposingStateControl } from "comps/controls/codeStateControl"; +import { ColumnOptionControl } from "comps/controls/optionsControl"; +import { styleControl } from "comps/controls/styleControl"; +import { ResponsiveLayoutRowStyle, ResponsiveLayoutRowStyleType, ResponsiveLayoutColStyleType, TabContainerStyle, TabContainerStyleType, heightCalculator, widthCalculator, ResponsiveLayoutColStyle } from "comps/controls/styleControlConstants"; +import { sameTypeMap, UICompBuilder, withDefault } from "comps/generators"; +import { addMapChildAction } from "comps/generators/sameTypeMap"; +import { NameConfigHidden, withExposingConfigs } from "comps/generators/withExposing"; +import { NameGenerator } from "comps/utils"; +import { Section, sectionNames } from "lowcoder-design"; +import { HintPlaceHolder } from "lowcoder-design"; +import _ from "lodash"; +import React, { useContext } from "react"; +import styled from "styled-components"; +import { IContainer } from "../containerBase/iContainer"; +import { SimpleContainerComp } from "../containerBase/simpleContainerComp"; +import { CompTree, mergeCompTrees } from "../containerBase/utils"; +import { + ContainerBaseProps, + gridItemCompToGridItems, + InnerGrid, +} from "../containerComp/containerView"; +import { BackgroundColorContext } from "comps/utils/backgroundColorContext"; +import { trans } from "i18n"; +import { EditorContext } from "comps/editorState"; +import { checkIsMobile } from "util/commonUtils"; +import { messageInstance } from "lowcoder-design"; +import { BoolControl } from "comps/controls/boolControl"; + +const RowWrapper = styled(Row)<{$style: ResponsiveLayoutRowStyleType}>` + height: 100%; + border: 1px solid ${(props) => props.$style.border}; + border-radius: ${(props) => props.$style.radius}; + padding: ${(props) => props.$style.padding}; + background-color: ${(props) => props.$style.background}; +`; + +const ColWrapper = styled(InnerGrid)<{ + $style: ResponsiveLayoutColStyleType, + $minWidth: string, +}>` + height: 100%; + min-width: ${(props) => props.$minWidth}; + border: 1px solid ${(props) => props.$style.border}; + border-radius: ${(props) => props.$style.radius}; + padding: ${(props) => props.$style.padding}; + background-color: ${(props) => props.$style.background}; + flex: 1 1 auto; +`; + +const childrenMap = { + columns: ColumnOptionControl, + selectedTabKey: stringExposingStateControl("key", "Tab1"), + containers: withDefault(sameTypeMap(SimpleContainerComp), { + 0: { view: {}, layout: {} }, + 1: { view: {}, layout: {} }, + }), + autoHeight: AutoHeightControl, + rowBreak: withDefault(BoolControl, false), + rowStyle: styleControl(ResponsiveLayoutRowStyle), + columnStyle: styleControl(ResponsiveLayoutColStyle), +}; + +type ViewProps = RecordConstructorToView; +type ResponsiveLayoutProps = ViewProps & { dispatch: DispatchType }; +type ColumnContainerProps = Omit & { + style: ResponsiveLayoutColStyleType + minWidth: string, +} + +const ColumnContainer = (props: ColumnContainerProps) => { + return ( + + ); +}; + + +const ResponsiveLayout = (props: ResponsiveLayoutProps) => { + let { + columns, + containers, + dispatch, + rowBreak, + rowStyle, + columnStyle, + } = props; + console.log(props) + + const editorState = useContext(EditorContext); + const maxWidth = editorState.getAppSettings().maxWidth; + const isMobile = checkIsMobile(maxWidth); + const paddingWidth = isMobile ? 8 : 20; + + return ( + + + {columns.map(column => { + const id = String(column.id); + const childDispatch = wrapDispatch(wrapDispatch(dispatch, "containers"), id); + if(!containers[id]) return null + const containerProps = containers[id].children; + const columnCustomStyle = { + margin: !_.isEmpty(column.margin) ? column.margin : columnStyle.margin, + padding: !_.isEmpty(column.padding) ? column.padding : columnStyle.padding, + border: !_.isEmpty(column.border) ? column.border : columnStyle.border, + radius: !_.isEmpty(column.radius) ? column.radius : columnStyle.radius, + background: !_.isEmpty(column.background) ? column.background : columnStyle.background, + } + console.log(column); + return ( + + ) + }) + } + + + ); +}; + +export const ResponsiveLayoutBaseComp = (function () { + return new UICompBuilder(childrenMap, (props, dispatch) => { + return ( + + ); + }) + .setPropertyViewFn((children) => { + return ( + <> +
+ {children.columns.propertyView({ + title: trans("responsiveLayout.column"), + newOptionLabel: "Column", + })} + {children.autoHeight.getPropertyView()} +
+
+ {children.rowBreak.propertyView({ + label: trans("responsiveLayout.rowBreak") + })} +
+
+ {children.rowStyle.getPropertyView()} +
+
+ {children.columnStyle.getPropertyView()} +
+ + ); + }) + .build(); +})(); + +class ResponsiveLayoutImplComp extends ResponsiveLayoutBaseComp implements IContainer { + private syncContainers(): this { + const columns = this.children.columns.getView(); + const ids: Set = new Set(columns.map((column) => String(column.id))); + let containers = this.children.containers.getView(); + // delete + const actions: CompAction[] = []; + Object.keys(containers).forEach((id) => { + if (!ids.has(id)) { + // log.debug("syncContainers delete. ids=", ids, " id=", id); + actions.push(wrapChildAction("containers", wrapChildAction(id, deleteCompAction()))); + } + }); + // new + ids.forEach((id) => { + if (!containers.hasOwnProperty(id)) { + // log.debug("syncContainers new containers: ", containers, " id: ", id); + actions.push( + wrapChildAction("containers", addMapChildAction(id, { layout: {}, items: {} })) + ); + } + }); + // log.debug("syncContainers. actions: ", actions); + let instance = this; + actions.forEach((action) => { + instance = instance.reduce(action); + }); + return instance; + } + + override reduce(action: CompAction): this { + const columns = this.children.columns.getView(); + if (action.type === CompActionTypes.CUSTOM) { + const value = action.value as JSONObject; + if (value.type === "push") { + const itemValue = value.value as JSONObject; + if (_.isEmpty(itemValue.key)) itemValue.key = itemValue.label; + action = { + ...action, + value: { + ...value, + value: { ...itemValue }, + }, + } as CompAction; + } + if (value.type === "delete" && columns.length <= 1) { + messageInstance.warning(trans("responsiveLayout.atLeastOneColumnError")); + // at least one column + return this; + } + } + // log.debug("before super reduce. action: ", action); + let newInstance = super.reduce(action); + if (action.type === CompActionTypes.UPDATE_NODES_V2) { + // Need eval to get the value in StringControl + newInstance = newInstance.syncContainers(); + } + // log.debug("reduce. instance: ", this, " newInstance: ", newInstance); + return newInstance; + } + + realSimpleContainer(key?: string): SimpleContainerComp | undefined { + let selectedTabKey = this.children.selectedTabKey.getView().value; + const columns = this.children.columns.getView(); + const selectedTab = columns.find((column) => column.key === selectedTabKey) ?? columns[0]; + const id = String(selectedTab.id); + if (_.isNil(key)) return this.children.containers.children[id]; + return Object.values(this.children.containers.children).find((container) => + container.realSimpleContainer(key) + ); + } + + getCompTree(): CompTree { + const containerMap = this.children.containers.getView(); + const compTrees = Object.values(containerMap).map((container) => container.getCompTree()); + return mergeCompTrees(compTrees); + } + + findContainer(key: string): IContainer | undefined { + const containerMap = this.children.containers.getView(); + for (const container of Object.values(containerMap)) { + const foundContainer = container.findContainer(key); + if (foundContainer) { + return foundContainer === container ? this : foundContainer; + } + } + return undefined; + } + + getPasteValue(nameGenerator: NameGenerator): JSONValue { + const containerMap = this.children.containers.getView(); + const containerPasteValueMap = _.mapValues(containerMap, (container) => + container.getPasteValue(nameGenerator) + ); + + return { ...this.toJsonValue(), containers: containerPasteValueMap }; + } + + override autoHeight(): boolean { + return this.children.autoHeight.getView(); + } +} + +export const ResponsiveLayoutComp = withExposingConfigs( + ResponsiveLayoutImplComp, + [ NameConfigHidden] +); diff --git a/client/packages/lowcoder/src/comps/controls/optionsControl.tsx b/client/packages/lowcoder/src/comps/controls/optionsControl.tsx index 05f1f6d63..96c87ba6a 100644 --- a/client/packages/lowcoder/src/comps/controls/optionsControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/optionsControl.tsx @@ -1,5 +1,5 @@ import { ViewDocIcon } from "assets/icons"; -import { ArrayControl, BoolCodeControl, StringControl } from "comps/controls/codeControl"; +import { ArrayControl, BoolCodeControl, RadiusControl, StringControl } from "comps/controls/codeControl"; import { dropdownControl, LeftRightControl } from "comps/controls/dropdownControl"; import { IconControl } from "comps/controls/iconControl"; import { MultiCompBuilder, valueComp, withContext, withDefault } from "comps/generators"; @@ -27,6 +27,7 @@ import { getNextEntityName } from "util/stringUtils"; import { JSONValue } from "util/jsonTypes"; import { ButtonEventHandlerControl } from "./eventHandlerControl"; import { ControlItemCompBuilder } from "comps/generators/controlCompBuilder"; +import { ColorControl } from "./colorControl"; const OptionTypes = [ { @@ -521,3 +522,51 @@ export const TabsOptionControl = manualOptionsControl(TabsOption, { uniqField: "key", autoIncField: "id", }); + +const ColumnOption = new MultiCompBuilder( + { + id: valueComp(-1), + label: StringControl, + key: StringControl, + minWidth: withDefault(RadiusControl, ""), + background: withDefault(ColorControl, ""), + border: withDefault(ColorControl, ""), + radius: withDefault(RadiusControl, ""), + margin: withDefault(StringControl, ""), + padding: withDefault(StringControl, ""), + }, + (props) => props +) +.setPropertyViewFn((children) => ( + <> + {children.minWidth.propertyView({ + label: trans('responsiveLayout.minWidth') + })} + {children.background.propertyView({ + label: trans('style.background') + })} + {children.border.propertyView({ + label: trans('style.border') + })} + {children.radius.propertyView({ + label: trans('style.borderRadius') + })} + {children.margin.propertyView({ + label: trans('style.margin') + })} + {children.padding.propertyView({ + label: trans('style.padding') + })} + +)) + .build(); + +export const ColumnOptionControl = manualOptionsControl(ColumnOption, { + initOptions: [ + { id: 0, key: "Column1", label: "Column1" }, + { id: 1, key: "Column2", label: "Column2" }, + ], + uniqField: "key", + autoIncField: "id", +}); + diff --git a/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx b/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx index 5d650faea..19c92160a 100644 --- a/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx +++ b/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx @@ -905,6 +905,18 @@ export const LottieStyle = [ ] as const; ///////////////////// +export const ResponsiveLayoutRowStyle = [ + ...BG_STATIC_BORDER_RADIUS, + MARGIN, + PADDING, +] as const; + +export const ResponsiveLayoutColStyle = [ + ...BG_STATIC_BORDER_RADIUS, + MARGIN, + PADDING, +] as const; + export const CarouselStyle = [getBackground("canvas")] as const; export const RichTextEditorStyle = [getStaticBorder(), RADIUS] as const; @@ -943,6 +955,8 @@ export type CalendarStyleType = StyleConfigType; export type SignatureStyleType = StyleConfigType; export type CarouselStyleType = StyleConfigType; export type RichTextEditorStyleType = StyleConfigType; +export type ResponsiveLayoutRowStyleType = StyleConfigType; +export type ResponsiveLayoutColStyleType = StyleConfigType; export function widthCalculator(margin: string) { const marginArr = margin?.trim().split(" ") || ""; diff --git a/client/packages/lowcoder/src/comps/index.tsx b/client/packages/lowcoder/src/comps/index.tsx index 5dc0f2923..e98396afb 100644 --- a/client/packages/lowcoder/src/comps/index.tsx +++ b/client/packages/lowcoder/src/comps/index.tsx @@ -126,6 +126,7 @@ import { MentionComp } from "./comps/textInputComp/mentionComp"; import { AutoCompleteComp } from "./comps/autoCompleteComp/autoCompleteComp" //Added by Aqib Mirza import { JsonLottieComp } from "./comps/jsonComp/jsonLottieComp"; +import { ResponsiveLayoutComp } from "./comps/responsiveLayout"; type Registry = { [key in UICompType]?: UICompManifest; @@ -879,6 +880,21 @@ const uiCompMap: Registry = { layoutInfo: { w: 7, h: 5, + } + }, + responsiveLayout: { + name: trans("uiComp.responsiveLayoutCompName"), + enName: "Responsive Layout", + description: trans("uiComp.responsiveLayoutCompDesc"), + categories: ["container", "common"], + icon: TabbedContainerCompIcon, + keywords: trans("uiComp.responsiveLayoutCompKeywords"), + comp: ResponsiveLayoutComp, + withoutLoading: true, + layoutInfo: { + w: 15, + h: 27, + delayCollision: true, }, }, }; diff --git a/client/packages/lowcoder/src/comps/uiCompRegistry.ts b/client/packages/lowcoder/src/comps/uiCompRegistry.ts index 6cd63e920..523409a01 100644 --- a/client/packages/lowcoder/src/comps/uiCompRegistry.ts +++ b/client/packages/lowcoder/src/comps/uiCompRegistry.ts @@ -114,6 +114,7 @@ export type UICompType = | "timeline" | "mention" | "autocomplete" + | "responsiveLayout" export const uiCompRegistry = {} as Record; diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 941a77767..8f5fe98f0 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -342,6 +342,7 @@ export const en = { containerheaderpadding: "Header Padding", containerfooterpadding: "Footer Padding", containerbodypadding: "Body Padding", + minWidth: "Minimum Width", }, export: { hiddenDesc: "If true, the component is hidden", @@ -853,6 +854,9 @@ export const en = { autoCompleteCompName: "autoComplete", autoCompleteCompDesc: "autoComplete", autoCompleteCompKeywords: "", + responsiveLayoutCompName: "Responsive Layout", + responsiveLayoutCompDesc: "Responsive Layout", + responsiveLayoutCompKeywords: "", }, comp: { menuViewDocs: "View documentation", @@ -2505,4 +2509,18 @@ export const en = { helpLabel: "label", helpValue: "value", }, + responsiveLayout: { + column: "Columns", + atLeastOneColumnError: "Responsive layout keeps at least one Column", + columnsSpacing: "Columns Spacing(px)", + horizontal: "Horizontal", + vertical: "Vertical", + mobile: "Mobile", + tablet: "Tablet", + desktop: "Desktop", + rowStyle: "Row Style", + columnStyle: "Column Style", + minWidth: "Minimum Width", + rowBreak: "Row Break", + }, }; diff --git a/client/packages/lowcoder/src/i18n/locales/zh.ts b/client/packages/lowcoder/src/i18n/locales/zh.ts index 7fb2416d5..d1d653692 100644 --- a/client/packages/lowcoder/src/i18n/locales/zh.ts +++ b/client/packages/lowcoder/src/i18n/locales/zh.ts @@ -338,6 +338,7 @@ style: { containerheaderpadding: "上内边距", containerfooterpadding: "下内边距", containerbodypadding: "内边距", + minWidth: "最小宽度", }, export: { hiddenDesc: "如果为true,则隐藏组件", @@ -836,6 +837,9 @@ uiComp: { autoCompleteCompName: "自动完成", autoCompleteCompDesc: "自动完成", autoCompleteCompKeywords: "zdwc", + responsiveLayoutCompName: "响应式布局", + responsiveLayoutCompDesc: "响应式布局", + responsiveLayoutCompKeywords: "", }, comp: { menuViewDocs: "查看文档", @@ -2495,5 +2499,19 @@ timeLine: { helpLabel: "标签", helpValue: "值", }, + responsiveLayout: { + column: "列", + atLeastOneColumnError: "响应式布局至少保留一列", + columnsSpacing: "列间距(px)", + horizontal: "水平的", + vertical: "垂直的", + mobile: "移动的", + tablet: "药片", + desktop: "桌面", + rowStyle: "行式", + columnStyle: "栏目样式", + minWidth: "最小宽度", + rowBreak: "断行", + } }; diff --git a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx index a09a9a56e..c7e185abd 100644 --- a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx +++ b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx @@ -107,4 +107,5 @@ export const CompStateIcon: { timeline: , mention: , autocomplete: , + responsiveLayout: , }; diff --git a/client/packages/lowcoder/src/pages/editor/editorView.tsx b/client/packages/lowcoder/src/pages/editor/editorView.tsx index d8b17b0ac..07f8d5aeb 100644 --- a/client/packages/lowcoder/src/pages/editor/editorView.tsx +++ b/client/packages/lowcoder/src/pages/editor/editorView.tsx @@ -302,7 +302,6 @@ function EditorView(props: EditorViewProps) { setMenuKey(params.key); }; const appSettingsComp = editorState.getAppSettingsComp(); - return ( { From 70561a0eb31e6879f73e64887406290a83c5fdb8 Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Fri, 18 Aug 2023 19:32:37 +0500 Subject: [PATCH 2/8] fix: layout default style --- .../src/comps/comps/responsiveLayout/responsiveLayout.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx index cd230fb5e..24e771d3c 100644 --- a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx +++ b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx @@ -61,7 +61,12 @@ const childrenMap = { }), autoHeight: AutoHeightControl, rowBreak: withDefault(BoolControl, false), - rowStyle: styleControl(ResponsiveLayoutRowStyle), + rowStyle: withDefault(styleControl(ResponsiveLayoutRowStyle), { + background: 'transparent', + border: 'transparent', + margin: '0', + padding: '0', + }), columnStyle: styleControl(ResponsiveLayoutColStyle), }; From 41c491c9b205bd8989da85df54b96cdb0227331a Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Mon, 21 Aug 2023 03:35:49 +0500 Subject: [PATCH 3/8] feat: added columns per row, vertical and horizonal spacing option --- .../src/icons/icon-responsive-layout-comp.svg | 1 + .../lowcoder-design/src/icons/icon-width.svg | 1 + .../lowcoder-design/src/icons/index.ts | 2 + .../responsiveLayout/responsiveLayout.tsx | 99 +++++++++++++------ .../comps/comps/tabs/tabbedContainerComp.tsx | 14 --- .../src/comps/controls/optionsControl.tsx | 70 +++++++++++-- client/packages/lowcoder/src/comps/index.tsx | 3 +- .../packages/lowcoder/src/i18n/locales/en.ts | 3 +- .../packages/lowcoder/src/i18n/locales/zh.ts | 3 +- .../src/pages/editor/editorConstants.tsx | 3 +- 10 files changed, 141 insertions(+), 58 deletions(-) create mode 100644 client/packages/lowcoder-design/src/icons/icon-responsive-layout-comp.svg create mode 100644 client/packages/lowcoder-design/src/icons/icon-width.svg diff --git a/client/packages/lowcoder-design/src/icons/icon-responsive-layout-comp.svg b/client/packages/lowcoder-design/src/icons/icon-responsive-layout-comp.svg new file mode 100644 index 000000000..f26e79095 --- /dev/null +++ b/client/packages/lowcoder-design/src/icons/icon-responsive-layout-comp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/packages/lowcoder-design/src/icons/icon-width.svg b/client/packages/lowcoder-design/src/icons/icon-width.svg new file mode 100644 index 000000000..1db8d6356 --- /dev/null +++ b/client/packages/lowcoder-design/src/icons/icon-width.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/packages/lowcoder-design/src/icons/index.ts b/client/packages/lowcoder-design/src/icons/index.ts index 4ac1b051e..6c9c2eb2b 100644 --- a/client/packages/lowcoder-design/src/icons/index.ts +++ b/client/packages/lowcoder-design/src/icons/index.ts @@ -291,3 +291,5 @@ export { ReactComponent as TimeLineIcon } from "icons/icon-timeline-comp.svg" export { ReactComponent as LottieIcon } from "icons/icon-lottie.svg"; export { ReactComponent as MentionIcon } from "icons/icon-mention-comp.svg"; export { ReactComponent as AutoCompleteCompIcon } from "icons/icon-autocomplete-comp.svg"; +export { ReactComponent as WidthIcon } from "icons/icon-width.svg"; +export { ReactComponent as ResponsiveLayoutCompIcon } from "icons/icon-responsive-layout-comp.svg"; diff --git a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx index 24e771d3c..bb3651a24 100644 --- a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx +++ b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx @@ -1,4 +1,4 @@ -import { Row } from "antd"; +import { Row, Col } from "antd"; import { JSONObject, JSONValue } from "util/jsonTypes"; import { CompAction, CompActionTypes, deleteCompAction, wrapChildAction } from "lowcoder-core"; import { DispatchType, RecordConstructorToView, wrapDispatch } from "lowcoder-core"; @@ -30,6 +30,7 @@ import { EditorContext } from "comps/editorState"; import { checkIsMobile } from "util/commonUtils"; import { messageInstance } from "lowcoder-design"; import { BoolControl } from "comps/controls/boolControl"; +import { NumberControl } from "comps/controls/codeControl"; const RowWrapper = styled(Row)<{$style: ResponsiveLayoutRowStyleType}>` height: 100%; @@ -37,19 +38,21 @@ const RowWrapper = styled(Row)<{$style: ResponsiveLayoutRowStyleType}>` border-radius: ${(props) => props.$style.radius}; padding: ${(props) => props.$style.padding}; background-color: ${(props) => props.$style.background}; + overflow-x: auto; `; -const ColWrapper = styled(InnerGrid)<{ +const ColWrapper = styled(Col)<{ $style: ResponsiveLayoutColStyleType, - $minWidth: string, + $minWidth?: string, + $backgroundImage?: string, }>` height: 100%; min-width: ${(props) => props.$minWidth}; - border: 1px solid ${(props) => props.$style.border}; - border-radius: ${(props) => props.$style.radius}; - padding: ${(props) => props.$style.padding}; - background-color: ${(props) => props.$style.background}; - flex: 1 1 auto; + + > div { + background: ${(props) => `center / cover url(${props.$backgroundImage}) no-repeat, ${props.$style.background} !important`}; + border: 1px solid ${(props) => props.$style.border} !important; + } `; const childrenMap = { @@ -61,31 +64,28 @@ const childrenMap = { }), autoHeight: AutoHeightControl, rowBreak: withDefault(BoolControl, false), - rowStyle: withDefault(styleControl(ResponsiveLayoutRowStyle), { - background: 'transparent', - border: 'transparent', - margin: '0', - padding: '0', - }), - columnStyle: styleControl(ResponsiveLayoutColStyle), + rowStyle: withDefault(styleControl(ResponsiveLayoutRowStyle), {}), + columnStyle: withDefault(styleControl(ResponsiveLayoutColStyle), {}), + columnPerRowLG: withDefault(NumberControl, 4), + columnPerRowMD: withDefault(NumberControl, 2), + columnPerRowSM: withDefault(NumberControl, 1), + verticalSpacing: withDefault(NumberControl, 8), + horizontalSpacing: withDefault(NumberControl, 8), }; type ViewProps = RecordConstructorToView; type ResponsiveLayoutProps = ViewProps & { dispatch: DispatchType }; type ColumnContainerProps = Omit & { style: ResponsiveLayoutColStyleType - minWidth: string, } const ColumnContainer = (props: ColumnContainerProps) => { return ( - ); }; @@ -99,8 +99,12 @@ const ResponsiveLayout = (props: ResponsiveLayoutProps) => { rowBreak, rowStyle, columnStyle, + columnPerRowLG, + columnPerRowMD, + columnPerRowSM, + verticalSpacing, + horizontalSpacing, } = props; - console.log(props) const editorState = useContext(EditorContext); const maxWidth = editorState.getAppSettings().maxWidth; @@ -112,31 +116,43 @@ const ResponsiveLayout = (props: ResponsiveLayoutProps) => { {columns.map(column => { const id = String(column.id); const childDispatch = wrapDispatch(wrapDispatch(dispatch, "containers"), id); if(!containers[id]) return null const containerProps = containers[id].children; + const columnCustomStyle = { margin: !_.isEmpty(column.margin) ? column.margin : columnStyle.margin, padding: !_.isEmpty(column.padding) ? column.padding : columnStyle.padding, - border: !_.isEmpty(column.border) ? column.border : columnStyle.border, radius: !_.isEmpty(column.radius) ? column.radius : columnStyle.radius, + border: !_.isEmpty(column.border) ? column.border : columnStyle.border, background: !_.isEmpty(column.background) ? column.background : columnStyle.background, } - console.log(column); + const noOfColumns = columns.length; return ( - + lg={24/(noOfColumns < columnPerRowLG ? noOfColumns : columnPerRowLG)} + md={24/(noOfColumns < columnPerRowMD ? noOfColumns : columnPerRowMD)} + sm={24/(noOfColumns < columnPerRowSM ? noOfColumns : columnPerRowSM)} + $style={columnCustomStyle} + $minWidth={column.minWidth} + $backgroundImage={ + !_.isEmpty(column.backgroundImage) && column.backgroundImage + } + > + + ) }) } @@ -166,6 +182,25 @@ export const ResponsiveLayoutBaseComp = (function () { label: trans("responsiveLayout.rowBreak") })} +
+ {children.columnPerRowLG.propertyView({ + label: trans("responsiveLayout.desktop") + })} + {children.columnPerRowMD.propertyView({ + label: trans("responsiveLayout.tablet") + })} + {children.columnPerRowSM.propertyView({ + label: trans("responsiveLayout.mobile") + })} +
+
+ {children.horizontalSpacing.propertyView({ + label: trans("responsiveLayout.horizontal") + })} + {children.verticalSpacing.propertyView({ + label: trans("responsiveLayout.vertical") + })} +
{children.rowStyle.getPropertyView()}
diff --git a/client/packages/lowcoder/src/comps/comps/tabs/tabbedContainerComp.tsx b/client/packages/lowcoder/src/comps/comps/tabs/tabbedContainerComp.tsx index cfed15f55..f4d04bff7 100644 --- a/client/packages/lowcoder/src/comps/comps/tabs/tabbedContainerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tabs/tabbedContainerComp.tsx @@ -196,20 +196,6 @@ const TabbedContainer = (props: TabbedContainerProps) => { ) } - // return ( - // - // - // - // - // - // ); }) return ( diff --git a/client/packages/lowcoder/src/comps/controls/optionsControl.tsx b/client/packages/lowcoder/src/comps/controls/optionsControl.tsx index 96c87ba6a..24dd5f42f 100644 --- a/client/packages/lowcoder/src/comps/controls/optionsControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/optionsControl.tsx @@ -20,7 +20,16 @@ import { MultiBaseComp, withFunction, } from "lowcoder-core"; -import { AutoArea, controlItem, Option } from "lowcoder-design"; +import { + AutoArea, + CompressIcon, + controlItem, + ExpandIcon, + IconRadius, + Option, + WidthIcon, + ImageCompIcon, +} from "lowcoder-design"; import styled from "styled-components"; import { lastValueIfEqual } from "util/objectUtils"; import { getNextEntityName } from "util/stringUtils"; @@ -28,6 +37,7 @@ import { JSONValue } from "util/jsonTypes"; import { ButtonEventHandlerControl } from "./eventHandlerControl"; import { ControlItemCompBuilder } from "comps/generators/controlCompBuilder"; import { ColorControl } from "./colorControl"; +import { StringStateControl } from "./codeStateControl"; const OptionTypes = [ { @@ -523,6 +533,36 @@ export const TabsOptionControl = manualOptionsControl(TabsOption, { autoIncField: "id", }); +const StyledIcon = styled.span` + margin: 0 4px 0 14px; +`; + +const StyledContent = styled.div` + > div { + margin: 4px 0; + flex-direction: row; + gap: 4px 0px; + flex-wrap: wrap; + + > div:nth-of-type(1) { + flex: 0 0 96px; + + div { + line-height: 16px; + } + } + + > svg { + height: 30px; + width: 25px; + } + + > div:nth-of-type(2) { + flex: 1 1 auto; + } + } +`; + const ColumnOption = new MultiCompBuilder( { id: valueComp(-1), @@ -530,6 +570,7 @@ const ColumnOption = new MultiCompBuilder( key: StringControl, minWidth: withDefault(RadiusControl, ""), background: withDefault(ColorControl, ""), + backgroundImage: withDefault(StringControl, ""), border: withDefault(ColorControl, ""), radius: withDefault(RadiusControl, ""), margin: withDefault(StringControl, ""), @@ -538,26 +579,39 @@ const ColumnOption = new MultiCompBuilder( (props) => props ) .setPropertyViewFn((children) => ( - <> + {children.minWidth.propertyView({ - label: trans('responsiveLayout.minWidth') + label: trans('responsiveLayout.minWidth'), + preInputNode: , + placeholder: '3px', })} {children.background.propertyView({ - label: trans('style.background') + label: trans('style.background'), + })} + {children.backgroundImage.propertyView({ + label: `Background Image`, + // preInputNode: , + placeholder: 'https://temp.im/350x400', })} {children.border.propertyView({ label: trans('style.border') })} {children.radius.propertyView({ - label: trans('style.borderRadius') + label: trans('style.borderRadius'), + preInputNode: , + placeholder: '3px', })} {children.margin.propertyView({ - label: trans('style.margin') + label: trans('style.margin'), + preInputNode: , + placeholder: '3px', })} {children.padding.propertyView({ - label: trans('style.padding') + label: trans('style.padding'), + preInputNode: , + placeholder: '3px', })} - + )) .build(); diff --git a/client/packages/lowcoder/src/comps/index.tsx b/client/packages/lowcoder/src/comps/index.tsx index e98396afb..16668379d 100644 --- a/client/packages/lowcoder/src/comps/index.tsx +++ b/client/packages/lowcoder/src/comps/index.tsx @@ -96,6 +96,7 @@ import { LottieIcon, MentionIcon, AutoCompleteCompIcon, + ResponsiveLayoutCompIcon, } from "lowcoder-design"; import { defaultFormData, FormComp } from "./comps/formComp/formComp"; @@ -887,7 +888,7 @@ const uiCompMap: Registry = { enName: "Responsive Layout", description: trans("uiComp.responsiveLayoutCompDesc"), categories: ["container", "common"], - icon: TabbedContainerCompIcon, + icon: ResponsiveLayoutCompIcon, keywords: trans("uiComp.responsiveLayoutCompKeywords"), comp: ResponsiveLayoutComp, withoutLoading: true, diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 8f5fe98f0..df6de71c4 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -2512,6 +2512,7 @@ export const en = { responsiveLayout: { column: "Columns", atLeastOneColumnError: "Responsive layout keeps at least one Column", + columnsPerRow: "Columns per Row", columnsSpacing: "Columns Spacing(px)", horizontal: "Horizontal", vertical: "Vertical", @@ -2520,7 +2521,7 @@ export const en = { desktop: "Desktop", rowStyle: "Row Style", columnStyle: "Column Style", - minWidth: "Minimum Width", + minWidth: "Min. Width", rowBreak: "Row Break", }, }; diff --git a/client/packages/lowcoder/src/i18n/locales/zh.ts b/client/packages/lowcoder/src/i18n/locales/zh.ts index d1d653692..cfd5e5aa9 100644 --- a/client/packages/lowcoder/src/i18n/locales/zh.ts +++ b/client/packages/lowcoder/src/i18n/locales/zh.ts @@ -2502,6 +2502,7 @@ timeLine: { responsiveLayout: { column: "列", atLeastOneColumnError: "响应式布局至少保留一列", + columnsPerRow: "每行列数", columnsSpacing: "列间距(px)", horizontal: "水平的", vertical: "垂直的", @@ -2510,7 +2511,7 @@ timeLine: { desktop: "桌面", rowStyle: "行式", columnStyle: "栏目样式", - minWidth: "最小宽度", + minWidth: "分钟。宽度", rowBreak: "断行", } }; diff --git a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx index c7e185abd..345baf396 100644 --- a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx +++ b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx @@ -39,6 +39,7 @@ import { TimeLineIcon, MentionIcon, AutoCompleteCompIcon, + ResponsiveLayoutCompIcon, } from "lowcoder-design"; export const CompStateIcon: { @@ -107,5 +108,5 @@ export const CompStateIcon: { timeline: , mention: , autocomplete: , - responsiveLayout: , + responsiveLayout: , }; From fba6a026c59405b683d1fd5856cc92f18dac7dad Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Mon, 21 Aug 2023 18:49:04 +0500 Subject: [PATCH 4/8] fix: fixed issues related to column height --- .../responsiveLayout/responsiveLayout.tsx | 108 +++++++++--------- .../src/comps/controls/optionsControl.tsx | 4 +- 2 files changed, 54 insertions(+), 58 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx index bb3651a24..d11385a31 100644 --- a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx +++ b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx @@ -14,7 +14,7 @@ import { NameGenerator } from "comps/utils"; import { Section, sectionNames } from "lowcoder-design"; import { HintPlaceHolder } from "lowcoder-design"; import _ from "lodash"; -import React, { useContext } from "react"; +import React from "react"; import styled from "styled-components"; import { IContainer } from "../containerBase/iContainer"; import { SimpleContainerComp } from "../containerBase/simpleContainerComp"; @@ -26,8 +26,6 @@ import { } from "../containerComp/containerView"; import { BackgroundColorContext } from "comps/utils/backgroundColorContext"; import { trans } from "i18n"; -import { EditorContext } from "comps/editorState"; -import { checkIsMobile } from "util/commonUtils"; import { messageInstance } from "lowcoder-design"; import { BoolControl } from "comps/controls/boolControl"; import { NumberControl } from "comps/controls/codeControl"; @@ -44,14 +42,10 @@ const RowWrapper = styled(Row)<{$style: ResponsiveLayoutRowStyleType}>` const ColWrapper = styled(Col)<{ $style: ResponsiveLayoutColStyleType, $minWidth?: string, - $backgroundImage?: string, }>` - height: 100%; min-width: ${(props) => props.$minWidth}; - > div { - background: ${(props) => `center / cover url(${props.$backgroundImage}) no-repeat, ${props.$style.background} !important`}; - border: 1px solid ${(props) => props.$style.border} !important; + height: 100%; } `; @@ -76,7 +70,7 @@ const childrenMap = { type ViewProps = RecordConstructorToView; type ResponsiveLayoutProps = ViewProps & { dispatch: DispatchType }; type ColumnContainerProps = Omit & { - style: ResponsiveLayoutColStyleType + style: ResponsiveLayoutColStyleType, } const ColumnContainer = (props: ColumnContainerProps) => { @@ -106,57 +100,59 @@ const ResponsiveLayout = (props: ResponsiveLayoutProps) => { horizontalSpacing, } = props; - const editorState = useContext(EditorContext); - const maxWidth = editorState.getAppSettings().maxWidth; - const isMobile = checkIsMobile(maxWidth); - const paddingWidth = isMobile ? 8 : 20; - return ( - - {columns.map(column => { - const id = String(column.id); - const childDispatch = wrapDispatch(wrapDispatch(dispatch, "containers"), id); - if(!containers[id]) return null - const containerProps = containers[id].children; +
+ + {columns.map(column => { + const id = String(column.id); + const childDispatch = wrapDispatch(wrapDispatch(dispatch, "containers"), id); + if(!containers[id]) return null + const containerProps = containers[id].children; - const columnCustomStyle = { - margin: !_.isEmpty(column.margin) ? column.margin : columnStyle.margin, - padding: !_.isEmpty(column.padding) ? column.padding : columnStyle.padding, - radius: !_.isEmpty(column.radius) ? column.radius : columnStyle.radius, - border: !_.isEmpty(column.border) ? column.border : columnStyle.border, - background: !_.isEmpty(column.background) ? column.background : columnStyle.background, + const columnCustomStyle = { + margin: !_.isEmpty(column.margin) ? column.margin : columnStyle.margin, + padding: !_.isEmpty(column.padding) ? column.padding : columnStyle.padding, + radius: !_.isEmpty(column.radius) ? column.radius : columnStyle.radius, + border: !_.isEmpty(column.border) ? column.border : columnStyle.border, + background: !_.isEmpty(column.background) ? column.background : columnStyle.background, + } + const noOfColumns = columns.length; + let backgroundStyle = columnCustomStyle.background; + if(!_.isEmpty(column.backgroundImage)) { + backgroundStyle = `center / cover url('${column.backgroundImage}') no-repeat, ${backgroundStyle}`; + } + return ( + + + + ) + }) } - const noOfColumns = columns.length; - return ( - - - - ) - }) - } - + +
); }; diff --git a/client/packages/lowcoder/src/comps/controls/optionsControl.tsx b/client/packages/lowcoder/src/comps/controls/optionsControl.tsx index 24dd5f42f..4f7606eef 100644 --- a/client/packages/lowcoder/src/comps/controls/optionsControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/optionsControl.tsx @@ -573,8 +573,8 @@ const ColumnOption = new MultiCompBuilder( backgroundImage: withDefault(StringControl, ""), border: withDefault(ColorControl, ""), radius: withDefault(RadiusControl, ""), - margin: withDefault(StringControl, ""), - padding: withDefault(StringControl, ""), + margin: withDefault(StringControl, "0px"), + padding: withDefault(StringControl, "0px"), }, (props) => props ) From a343a02a1b244ee13955caaa301aa7b88f8037fc Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Mon, 21 Aug 2023 19:49:43 +0500 Subject: [PATCH 5/8] fix: added match columns height switch --- .../comps/comps/responsiveLayout/responsiveLayout.tsx | 9 ++++++++- client/packages/lowcoder/src/i18n/locales/en.ts | 1 + client/packages/lowcoder/src/i18n/locales/zh.ts | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx index d11385a31..fa3692464 100644 --- a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx +++ b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx @@ -42,10 +42,11 @@ const RowWrapper = styled(Row)<{$style: ResponsiveLayoutRowStyleType}>` const ColWrapper = styled(Col)<{ $style: ResponsiveLayoutColStyleType, $minWidth?: string, + $matchColumnsHeight: boolean, }>` min-width: ${(props) => props.$minWidth}; > div { - height: 100%; + height: ${(props) => props.$matchColumnsHeight ? '100%' : 'auto'}; } `; @@ -58,6 +59,7 @@ const childrenMap = { }), autoHeight: AutoHeightControl, rowBreak: withDefault(BoolControl, false), + matchColumnsHeight: withDefault(BoolControl, false), rowStyle: withDefault(styleControl(ResponsiveLayoutRowStyle), {}), columnStyle: withDefault(styleControl(ResponsiveLayoutColStyle), {}), columnPerRowLG: withDefault(NumberControl, 4), @@ -91,6 +93,7 @@ const ResponsiveLayout = (props: ResponsiveLayoutProps) => { containers, dispatch, rowBreak, + matchColumnsHeight, rowStyle, columnStyle, columnPerRowLG, @@ -135,6 +138,7 @@ const ResponsiveLayout = (props: ResponsiveLayoutProps) => { xs={24/(noOfColumns < columnPerRowSM ? noOfColumns : columnPerRowSM)} $style={columnCustomStyle} $minWidth={column.minWidth} + $matchColumnsHeight={matchColumnsHeight} >
{children.columnPerRowLG.propertyView({ diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index df6de71c4..0d695a965 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -2523,5 +2523,6 @@ export const en = { columnStyle: "Column Style", minWidth: "Min. Width", rowBreak: "Row Break", + matchColumnsHeight: "Match Columns Height", }, }; diff --git a/client/packages/lowcoder/src/i18n/locales/zh.ts b/client/packages/lowcoder/src/i18n/locales/zh.ts index cfd5e5aa9..e2c61fe59 100644 --- a/client/packages/lowcoder/src/i18n/locales/zh.ts +++ b/client/packages/lowcoder/src/i18n/locales/zh.ts @@ -2513,6 +2513,7 @@ timeLine: { columnStyle: "栏目样式", minWidth: "分钟。宽度", rowBreak: "断行", + matchColumnsHeight: "匹配列高度", } }; From 0fcf7717775b6dacbe4a6525acaf1f160bb2c545 Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Tue, 22 Aug 2023 12:10:20 +0500 Subject: [PATCH 6/8] fix: remove selectedTabKey from childrenMap --- .../comps/responsiveLayout/responsiveLayout.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx index fa3692464..71e91af8d 100644 --- a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx +++ b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx @@ -6,7 +6,12 @@ import { AutoHeightControl } from "comps/controls/autoHeightControl"; import { stringExposingStateControl } from "comps/controls/codeStateControl"; import { ColumnOptionControl } from "comps/controls/optionsControl"; import { styleControl } from "comps/controls/styleControl"; -import { ResponsiveLayoutRowStyle, ResponsiveLayoutRowStyleType, ResponsiveLayoutColStyleType, TabContainerStyle, TabContainerStyleType, heightCalculator, widthCalculator, ResponsiveLayoutColStyle } from "comps/controls/styleControlConstants"; +import { + ResponsiveLayoutRowStyle, + ResponsiveLayoutRowStyleType, + ResponsiveLayoutColStyleType, + ResponsiveLayoutColStyle +} from "comps/controls/styleControlConstants"; import { sameTypeMap, UICompBuilder, withDefault } from "comps/generators"; import { addMapChildAction } from "comps/generators/sameTypeMap"; import { NameConfigHidden, withExposingConfigs } from "comps/generators/withExposing"; @@ -52,7 +57,6 @@ const ColWrapper = styled(Col)<{ const childrenMap = { columns: ColumnOptionControl, - selectedTabKey: stringExposingStateControl("key", "Tab1"), containers: withDefault(sameTypeMap(SimpleContainerComp), { 0: { view: {}, layout: {} }, 1: { view: {}, layout: {} }, @@ -278,11 +282,6 @@ class ResponsiveLayoutImplComp extends ResponsiveLayoutBaseComp implements ICont } realSimpleContainer(key?: string): SimpleContainerComp | undefined { - let selectedTabKey = this.children.selectedTabKey.getView().value; - const columns = this.children.columns.getView(); - const selectedTab = columns.find((column) => column.key === selectedTabKey) ?? columns[0]; - const id = String(selectedTab.id); - if (_.isNil(key)) return this.children.containers.children[id]; return Object.values(this.children.containers.children).find((container) => container.realSimpleContainer(key) ); From 2260bdbf7b0b48b56d18c91fb1aa15c465f9b764 Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Wed, 23 Aug 2023 13:34:09 +0500 Subject: [PATCH 7/8] fix: bug fixes --- .../responsiveLayout/responsiveLayout.tsx | 27 ++++++++++++------- .../src/comps/controls/optionsControl.tsx | 4 +-- .../packages/lowcoder/src/i18n/locales/en.ts | 4 ++- .../packages/lowcoder/src/i18n/locales/zh.ts | 4 ++- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx index 71e91af8d..f9d45018c 100644 --- a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx +++ b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx @@ -16,7 +16,7 @@ import { sameTypeMap, UICompBuilder, withDefault } from "comps/generators"; import { addMapChildAction } from "comps/generators/sameTypeMap"; import { NameConfigHidden, withExposingConfigs } from "comps/generators/withExposing"; import { NameGenerator } from "comps/utils"; -import { Section, sectionNames } from "lowcoder-design"; +import { Section, controlItem, sectionNames } from "lowcoder-design"; import { HintPlaceHolder } from "lowcoder-design"; import _ from "lodash"; import React from "react"; @@ -85,6 +85,7 @@ const ColumnContainer = (props: ColumnContainerProps) => { {...props} emptyRows={15} hintPlaceholder={HintPlaceHolder} + radius={props.style.radius} style={props.style} /> ); @@ -125,7 +126,7 @@ const ResponsiveLayout = (props: ResponsiveLayoutProps) => { margin: !_.isEmpty(column.margin) ? column.margin : columnStyle.margin, padding: !_.isEmpty(column.padding) ? column.padding : columnStyle.padding, radius: !_.isEmpty(column.radius) ? column.radius : columnStyle.radius, - border: !_.isEmpty(column.border) ? column.border : columnStyle.border, + border: `1px solid ${!_.isEmpty(column.border) ? column.border : columnStyle.border}`, background: !_.isEmpty(column.background) ? column.background : columnStyle.background, } const noOfColumns = columns.length; @@ -181,15 +182,15 @@ export const ResponsiveLayoutBaseComp = (function () { })} {children.autoHeight.getPropertyView()}
-
+
{children.rowBreak.propertyView({ label: trans("responsiveLayout.rowBreak") })} - {children.matchColumnsHeight.propertyView({ - label: trans("responsiveLayout.matchColumnsHeight") - })} -
-
+ {controlItem({}, ( +
+ {trans("responsiveLayout.columnsPerRow")} +
+ ))} {children.columnPerRowLG.propertyView({ label: trans("responsiveLayout.desktop") })} @@ -200,7 +201,15 @@ export const ResponsiveLayoutBaseComp = (function () { label: trans("responsiveLayout.mobile") })}
-
+
+ {children.matchColumnsHeight.propertyView({ + label: trans("responsiveLayout.matchColumnsHeight") + })} + {controlItem({}, ( +
+ {trans("responsiveLayout.columnsSpacing")} +
+ ))} {children.horizontalSpacing.propertyView({ label: trans("responsiveLayout.horizontal") })} diff --git a/client/packages/lowcoder/src/comps/controls/optionsControl.tsx b/client/packages/lowcoder/src/comps/controls/optionsControl.tsx index 4f7606eef..24dd5f42f 100644 --- a/client/packages/lowcoder/src/comps/controls/optionsControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/optionsControl.tsx @@ -573,8 +573,8 @@ const ColumnOption = new MultiCompBuilder( backgroundImage: withDefault(StringControl, ""), border: withDefault(ColorControl, ""), radius: withDefault(RadiusControl, ""), - margin: withDefault(StringControl, "0px"), - padding: withDefault(StringControl, "0px"), + margin: withDefault(StringControl, ""), + padding: withDefault(StringControl, ""), }, (props) => props ) diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index ef30a94af..58bc84f5d 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -2517,7 +2517,7 @@ export const en = { column: "Columns", atLeastOneColumnError: "Responsive layout keeps at least one Column", columnsPerRow: "Columns per Row", - columnsSpacing: "Columns Spacing(px)", + columnsSpacing: "Columns Spacing (px)", horizontal: "Horizontal", vertical: "Vertical", mobile: "Mobile", @@ -2528,5 +2528,7 @@ export const en = { minWidth: "Min. Width", rowBreak: "Row Break", matchColumnsHeight: "Match Columns Height", + rowLayout: "Row Layout", + columnsLayout: "Columns Layout", }, }; diff --git a/client/packages/lowcoder/src/i18n/locales/zh.ts b/client/packages/lowcoder/src/i18n/locales/zh.ts index 1556a0d84..7cdfb89b2 100644 --- a/client/packages/lowcoder/src/i18n/locales/zh.ts +++ b/client/packages/lowcoder/src/i18n/locales/zh.ts @@ -2507,7 +2507,7 @@ timeLine: { column: "列", atLeastOneColumnError: "响应式布局至少保留一列", columnsPerRow: "每行列数", - columnsSpacing: "列间距(px)", + columnsSpacing: "列间距 (px)", horizontal: "水平的", vertical: "垂直的", mobile: "移动的", @@ -2518,6 +2518,8 @@ timeLine: { minWidth: "分钟。宽度", rowBreak: "断行", matchColumnsHeight: "匹配列高度", + rowLayout: "行布局", + columnsLayout: "栏目布局", } }; From bb5cefd445cfe60d1e44848929f23430ba847da4 Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Wed, 23 Aug 2023 16:02:13 +0500 Subject: [PATCH 8/8] fix: fixed column margin/padding issue --- .../src/comps/comps/responsiveLayout/responsiveLayout.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx index f9d45018c..53b06ede3 100644 --- a/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx +++ b/client/packages/lowcoder/src/comps/comps/responsiveLayout/responsiveLayout.tsx @@ -3,7 +3,6 @@ import { JSONObject, JSONValue } from "util/jsonTypes"; import { CompAction, CompActionTypes, deleteCompAction, wrapChildAction } from "lowcoder-core"; import { DispatchType, RecordConstructorToView, wrapDispatch } from "lowcoder-core"; import { AutoHeightControl } from "comps/controls/autoHeightControl"; -import { stringExposingStateControl } from "comps/controls/codeStateControl"; import { ColumnOptionControl } from "comps/controls/optionsControl"; import { styleControl } from "comps/controls/styleControl"; import { @@ -50,6 +49,9 @@ const ColWrapper = styled(Col)<{ $matchColumnsHeight: boolean, }>` min-width: ${(props) => props.$minWidth}; + display: flex; + flex-direction: column; + > div { height: ${(props) => props.$matchColumnsHeight ? '100%' : 'auto'}; }