Skip to content

Commit a73890c

Browse files
committed
add style customization for hamburger menu mode
1 parent b15b10a commit a73890c

File tree

2 files changed

+117
-27
lines changed

2 files changed

+117
-27
lines changed

client/packages/lowcoder/src/comps/comps/layout/mobileTabLayout.tsx

Lines changed: 93 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { hiddenPropertyView } from "comps/utils/propertyUtils";
2020
import { dropdownControl } from "@lowcoder-ee/comps/controls/dropdownControl";
2121
import { DataOption, DataOptionType, menuItemStyleOptions, mobileNavJsonMenuItems, MobileModeOptions, MobileMode, HamburgerPositionOptions, DrawerPlacementOptions } from "./navLayoutConstants";
2222
import { styleControl } from "@lowcoder-ee/comps/controls/styleControl";
23-
import { NavLayoutItemActiveStyle, NavLayoutItemActiveStyleType, NavLayoutItemHoverStyle, NavLayoutItemHoverStyleType, NavLayoutItemStyle, NavLayoutItemStyleType, NavLayoutStyle, NavLayoutStyleType } from "@lowcoder-ee/comps/controls/styleControlConstants";
23+
import { HamburgerButtonStyle, DrawerContainerStyle, NavLayoutItemActiveStyle, NavLayoutItemActiveStyleType, NavLayoutItemHoverStyle, NavLayoutItemHoverStyleType, NavLayoutItemStyle, NavLayoutItemStyleType, NavLayoutStyle, NavLayoutStyleType } from "@lowcoder-ee/comps/controls/styleControlConstants";
2424
import Segmented from "antd/es/segmented";
2525
import { controlItem } from "components/control";
2626
import { check } from "@lowcoder-ee/util/convertUtils";
@@ -72,15 +72,23 @@ const HamburgerButton = styled.button<{
7272
$size: string;
7373
$position: string; // bottom-right | bottom-left | top-right | top-left
7474
$zIndex: number;
75+
$background?: string;
76+
$borderColor?: string;
77+
$radius?: string;
78+
$margin?: string;
79+
$padding?: string;
80+
$borderWidth?: string;
7581
}>`
7682
position: fixed;
7783
${(props) => (props.$position.includes('bottom') ? 'bottom: 16px;' : 'top: 16px;')}
7884
${(props) => (props.$position.includes('right') ? 'right: 16px;' : 'left: 16px;')}
7985
width: ${(props) => props.$size};
8086
height: ${(props) => props.$size};
81-
border-radius: 50%;
82-
border: 1px solid rgba(0,0,0,0.1);
83-
background: white;
87+
border-radius: ${(props) => props.$radius || '50%'};
88+
border: ${(props) => props.$borderWidth || '1px'} solid ${(props) => props.$borderColor || 'rgba(0,0,0,0.1)'};
89+
background: ${(props) => props.$background || 'white'};
90+
margin: ${(props) => props.$margin || '0px'};
91+
padding: ${(props) => props.$padding || '0px'};
8492
display: flex;
8593
align-items: center;
8694
justify-content: center;
@@ -108,16 +116,34 @@ const BurgerIcon = styled.div<{
108116
&::after { top: 6px; }
109117
`;
110118

119+
const IconWrapper = styled.div<{
120+
$iconColor?: string;
121+
}>`
122+
display: inline-flex;
123+
align-items: center;
124+
justify-content: center;
125+
svg {
126+
color: ${(p) => p.$iconColor || 'inherit'};
127+
fill: ${(p) => p.$iconColor || 'currentColor'};
128+
}
129+
`;
130+
111131
const DrawerContent = styled.div<{
112132
$background: string;
133+
$padding?: string;
134+
$borderColor?: string;
135+
$borderWidth?: string;
136+
$margin?: string;
113137
}>`
114138
background: ${(p) => p.$background};
115139
width: 100%;
116140
height: 100%;
117141
display: flex;
118142
flex-direction: column;
119-
padding: 12px;
143+
padding: ${(p) => p.$padding || '12px'};
144+
margin: ${(p) => p.$margin || '0px'};
120145
box-sizing: border-box;
146+
border: ${(p) => p.$borderWidth || '1px'} solid ${(p) => p.$borderColor || 'transparent'};
121147
`;
122148

123149
const DrawerHeader = styled.div`
@@ -425,7 +451,7 @@ function renderHamburgerLayoutSection(children: any): any {
425451
const drawerPlacement = children.drawerPlacement.getView();
426452
return (
427453
<>
428-
{children.hamburgerIcon.propertyView({ label: "MenuIcon" })}
454+
{children.hamburgerIcon.propertyView({ label: "Menu Icon" })}
429455
{children.drawerCloseIcon.propertyView({ label: "Close Icon" })}
430456
{children.hamburgerPosition.propertyView({ label: "Hamburger Position" })}
431457
{children.hamburgerSize.propertyView({ label: "Hamburger Size" })}
@@ -462,6 +488,8 @@ function renderVerticalLayoutSection(children: any): any {
462488
);
463489
}
464490

491+
492+
465493
let MobileTabLayoutTmp = (function () {
466494
const childrenMap = {
467495
onEvent: eventHandlerControl(EventOptions),
@@ -492,7 +520,7 @@ let MobileTabLayoutTmp = (function () {
492520
drawerCloseIcon: IconControl,
493521
hamburgerPosition: dropdownControl(HamburgerPositionOptions, "bottom-right"),
494522
hamburgerSize: withDefault(StringControl, "56px"),
495-
drawerPlacement: dropdownControl(DrawerPlacementOptions, "bottom"),
523+
drawerPlacement: dropdownControl(DrawerPlacementOptions, "right"),
496524
drawerHeight: withDefault(StringControl, "60%"),
497525
drawerWidth: withDefault(StringControl, "250px"),
498526
shadowOverlay: withDefault(BoolCodeControl, true),
@@ -506,6 +534,8 @@ let MobileTabLayoutTmp = (function () {
506534
navItemStyle: styleControl(NavLayoutItemStyle, 'navItemStyle'),
507535
navItemHoverStyle: styleControl(NavLayoutItemHoverStyle, 'navItemHoverStyle'),
508536
navItemActiveStyle: styleControl(NavLayoutItemActiveStyle, 'navItemActiveStyle'),
537+
hamburgerButtonStyle: styleControl(HamburgerButtonStyle, 'hamburgerButtonStyle'),
538+
drawerContainerStyle: styleControl(DrawerContainerStyle, 'drawerContainerStyle'),
509539
};
510540
return new MultiCompBuilder(childrenMap, (props, dispatch) => {
511541
return null;
@@ -524,10 +554,18 @@ let MobileTabLayoutTmp = (function () {
524554
? renderHamburgerLayoutSection(children)
525555
: renderVerticalLayoutSection(children)}
526556
</Section>
527-
<Section name={trans("navLayout.navStyle")}>
528-
{children.navStyle.getPropertyView()}
529-
</Section>
530-
<Section name={trans("navLayout.navItemStyle")}>
557+
{!isHamburgerMode && (
558+
<Section name={trans("navLayout.navStyle")}>
559+
{children.navStyle.getPropertyView()}
560+
</Section>
561+
)}
562+
563+
{isHamburgerMode && (
564+
<Section name={"Hamburger Button Style"}>
565+
{children.hamburgerButtonStyle.getPropertyView()}
566+
</Section>
567+
)}
568+
<Section name={isHamburgerMode ? "Drawer Item Style" : trans("navLayout.navItemStyle")}>
531569
{controlItem({}, (
532570
<Segmented
533571
block
@@ -540,6 +578,11 @@ let MobileTabLayoutTmp = (function () {
540578
{styleSegment === 'hover' && children.navItemHoverStyle.getPropertyView()}
541579
{styleSegment === 'active' && children.navItemActiveStyle.getPropertyView()}
542580
</Section>
581+
{isHamburgerMode && (
582+
<Section name={"Drawer Container Style"}>
583+
{children.drawerContainerStyle.getPropertyView()}
584+
</Section>
585+
)}
543586
</>
544587
);
545588
})
@@ -563,6 +606,7 @@ MobileTabLayoutTmp = withViewFn(MobileTabLayoutTmp, (comp) => {
563606
const hamburgerSize = comp.children.hamburgerSize.getView();
564607
const hamburgerIconComp = comp.children.hamburgerIcon;
565608
const drawerCloseIconComp = comp.children.drawerCloseIcon;
609+
const hamburgerButtonStyle = comp.children.hamburgerButtonStyle.getView();
566610
const drawerPlacement = comp.children.drawerPlacement.getView();
567611
const drawerHeight = comp.children.drawerHeight.getView();
568612
const drawerWidth = comp.children.drawerWidth.getView();
@@ -572,6 +616,7 @@ MobileTabLayoutTmp = withViewFn(MobileTabLayoutTmp, (comp) => {
572616
const maxWidth = comp.children.maxWidth.getView();
573617
const verticalAlignment = comp.children.verticalAlignment.getView();
574618
const showSeparator = comp.children.showSeparator.getView();
619+
const drawerContainerStyle = comp.children.drawerContainerStyle.getView();
575620
const bgColor = (useContext(ThemeContext)?.theme || defaultTheme).canvas;
576621
const onEvent = comp.children.onEvent.getView();
577622

@@ -626,6 +671,21 @@ MobileTabLayoutTmp = withViewFn(MobileTabLayoutTmp, (comp) => {
626671
backgroundStyle = `center / cover url('${backgroundImage}') no-repeat, ${backgroundStyle}`;
627672
}
628673

674+
const navigateToApp = (nextIndex: number) => {
675+
if (dataOptionType === DataOption.Manual) {
676+
const selectedTab = tabViews[nextIndex];
677+
if (selectedTab) {
678+
const url = [
679+
ALL_APPLICATIONS_URL,
680+
pathParam.applicationId,
681+
pathParam.viewMode,
682+
nextIndex,
683+
].join("/");
684+
selectedTab.children.action.act(url);
685+
}
686+
}
687+
};
688+
629689
const tabBarView = (
630690
<TabBarView
631691
onEvent={onEvent}
@@ -641,18 +701,7 @@ MobileTabLayoutTmp = withViewFn(MobileTabLayoutTmp, (comp) => {
641701
const nextIndex = Number(key);
642702
setTabIndex(nextIndex);
643703
// push URL with query/hash params
644-
if (dataOptionType === DataOption.Manual) {
645-
const selectedTab = tabViews[nextIndex];
646-
if (selectedTab) {
647-
const url = [
648-
ALL_APPLICATIONS_URL,
649-
pathParam.applicationId,
650-
pathParam.viewMode,
651-
nextIndex,
652-
].join("/");
653-
selectedTab.children.action.act(url);
654-
}
655-
}
704+
navigateToApp(nextIndex);
656705
}}
657706
readOnly={!!readOnly}
658707
canvasBg={bgColor}
@@ -682,11 +731,21 @@ MobileTabLayoutTmp = withViewFn(MobileTabLayoutTmp, (comp) => {
682731
$size={hamburgerSize}
683732
$position={hamburgerPosition}
684733
$zIndex={Layers.tabBar + 1}
734+
$background={hamburgerButtonStyle?.background}
735+
$borderColor={hamburgerButtonStyle?.border}
736+
$radius={hamburgerButtonStyle?.radius}
737+
$margin={hamburgerButtonStyle?.margin}
738+
$padding={hamburgerButtonStyle?.padding}
739+
$borderWidth={hamburgerButtonStyle?.borderWidth}
685740
onClick={() => setDrawerVisible(true)}
686741
>
687-
{hamburgerIconComp.toJsonValue()
688-
? hamburgerIconComp.getView()
689-
: <BurgerIcon $lineColor={navStyle.text} />}
742+
{hamburgerIconComp.toJsonValue() ? (
743+
<IconWrapper $iconColor={hamburgerButtonStyle?.iconFill}>
744+
{hamburgerIconComp.getView()}
745+
</IconWrapper>
746+
) : (
747+
<BurgerIcon $lineColor={hamburgerButtonStyle?.iconFill || navStyle.text} />
748+
)}
690749
</HamburgerButton>
691750
);
692751

@@ -707,7 +766,13 @@ MobileTabLayoutTmp = withViewFn(MobileTabLayoutTmp, (comp) => {
707766
mask={shadowOverlay}
708767
bodyStyle={drawerBodyStyle}
709768
>
710-
<DrawerContent $background={backgroundStyle}>
769+
<DrawerContent
770+
$background={drawerContainerStyle?.background || '#FFFFFF'}
771+
$padding={drawerContainerStyle?.padding}
772+
$borderColor={drawerContainerStyle?.border}
773+
$borderWidth={drawerContainerStyle?.borderWidth}
774+
$margin={drawerContainerStyle?.margin}
775+
>
711776
<DrawerHeader>
712777
<DrawerCloseButton
713778
aria-label="Close"
@@ -732,6 +797,7 @@ MobileTabLayoutTmp = withViewFn(MobileTabLayoutTmp, (comp) => {
732797
setTabIndex(index);
733798
setDrawerVisible(false);
734799
onEvent('click');
800+
navigateToApp(index);
735801
}}
736802
>
737803
{tab.children.icon.toJsonValue() ? (

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,30 @@ export const FloatButtonStyle = [
13821382
BORDER_WIDTH,
13831383
] as const;
13841384

1385+
export const HamburgerButtonStyle = [
1386+
getBackground(),
1387+
{
1388+
name: "iconFill",
1389+
label: trans("style.fill"),
1390+
depTheme: "primary",
1391+
depType: DEP_TYPE.SELF,
1392+
transformer: toSelf,
1393+
},
1394+
MARGIN,
1395+
PADDING,
1396+
BORDER,
1397+
RADIUS,
1398+
BORDER_WIDTH,
1399+
] as const;
1400+
1401+
export const DrawerContainerStyle = [
1402+
getBackground(),
1403+
MARGIN,
1404+
PADDING,
1405+
BORDER,
1406+
BORDER_WIDTH,
1407+
] as const;
1408+
13851409
export const TransferStyle = [
13861410
getStaticBackground(SURFACE_COLOR),
13871411
...STYLING_FIELDS_CONTAINER_SEQUENCE.filter(style=>style.name!=='rotation'),

0 commit comments

Comments
 (0)