Skip to content

Commit 0193614

Browse files
PageLayout Topbar; Smaller IslandGap, keeping resizeable area
1 parent 001a1a0 commit 0193614

3 files changed

Lines changed: 138 additions & 86 deletions

File tree

src/components/layout/page-layout/PageLayout.tsx

Lines changed: 112 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Flex, Spacer } from "@chakra-ui/react";
1+
import { Box, Flex, Spacer } from "@chakra-ui/react";
22
import { Children, ReactNode } from "react";
33
import { Main } from "../../Main";
44
import { Footer } from "../Footer";
@@ -7,6 +7,8 @@ import { Sidebar } from "../Sidebar";
77
import { ResizeHandle } from "./ResizeHandle";
88
import { useResize } from "./useResize";
99

10+
const ISLAND_GAP = 4;
11+
1012
interface Props {
1113
leftTopSidebarContent?: ReactNode;
1214
leftBottomSidebarContent?: ReactNode;
@@ -19,9 +21,10 @@ interface PageSidebarProps {
1921
side: "left" | "right";
2022
topContent?: ReactNode;
2123
bottomContent?: ReactNode;
22-
width: number;
24+
width: number | string;
2325
split: number;
2426
resizeHandleSize: number;
27+
islandGap: number;
2528
onResizeSplit: (delta: number) => void;
2629
}
2730

@@ -47,84 +50,114 @@ export function PageLayout({
4750
resizeLeftSidebarSplit,
4851
resizeRightSidebarSplit,
4952
MIN_MAIN_WIDTH,
50-
LAYOUT_PADDING,
5153
RESIZE_HANDLE_SIZE,
52-
} = useResize({ hasLeftSidebar, hasRightSidebar });
54+
} = useResize({
55+
hasLeftSidebar,
56+
hasRightSidebar,
57+
islandGap: ISLAND_GAP,
58+
});
5359

5460
return (
5561
<Flex
56-
direction="row"
62+
direction="column"
5763
width="100vw"
5864
height="100vh"
5965
overflow="hidden"
6066
bgColor="gray.100"
61-
padding={`${LAYOUT_PADDING}px`}
62-
gap={0}
67+
padding={`${ISLAND_GAP}px`}
68+
gap={`${ISLAND_GAP}px`}
6369
>
64-
{hasLeftSidebar && (
65-
<>
66-
<PageSidebar
67-
side="left"
68-
topContent={leftTopSidebarContent}
69-
bottomContent={leftBottomSidebarContent}
70-
width={leftWidth}
71-
split={leftSplit}
72-
resizeHandleSize={RESIZE_HANDLE_SIZE}
73-
onResizeSplit={resizeLeftSidebarSplit}
74-
/>
75-
76-
<ResizeHandle
77-
orientation="vertical"
78-
onResize={resizeLeftSidebar}
79-
size={RESIZE_HANDLE_SIZE}
80-
ariaLabel="Resize left sidebar"
81-
/>
82-
</>
83-
)}
70+
<Box>Hello World</Box>
8471

8572
<Flex
86-
minWidth={`${MIN_MAIN_WIDTH}px`}
73+
direction="row"
74+
width="100%"
8775
height="100%"
88-
flex={1}
8976
overflow="hidden"
77+
flex={1}
78+
gap={`${ISLAND_GAP}px`}
9079
>
91-
<Island>
92-
<Flex
93-
direction="column"
94-
width="100%"
95-
minHeight="100%"
96-
alignItems="center"
80+
{hasLeftSidebar && (
81+
<Box
82+
position="relative"
83+
width={`${leftWidth}px`}
84+
height="100%"
85+
flexShrink={0}
9786
>
98-
{/*<Hero title="ProvideQ" />*/}
99-
<Main>{children}</Main>
100-
101-
<Spacer mb="5rem" />
102-
<Footer />
103-
</Flex>
104-
</Island>
87+
<PageSidebar
88+
side="left"
89+
topContent={leftTopSidebarContent}
90+
bottomContent={leftBottomSidebarContent}
91+
width="100%"
92+
split={leftSplit}
93+
resizeHandleSize={RESIZE_HANDLE_SIZE}
94+
islandGap={ISLAND_GAP}
95+
onResizeSplit={resizeLeftSidebarSplit}
96+
/>
97+
98+
<ResizeHandle
99+
orientation="vertical"
100+
onResize={resizeLeftSidebar}
101+
size={RESIZE_HANDLE_SIZE}
102+
gapSize={ISLAND_GAP}
103+
edge="right"
104+
ariaLabel="Resize left sidebar"
105+
/>
106+
</Box>
107+
)}
108+
109+
<Flex
110+
minWidth={`${MIN_MAIN_WIDTH}px`}
111+
height="100%"
112+
flex={1}
113+
overflow="hidden"
114+
>
115+
<Island>
116+
<Flex
117+
direction="column"
118+
width="100%"
119+
minHeight="100%"
120+
alignItems="center"
121+
>
122+
{/*<Hero title="ProvideQ" />*/}
123+
<Main>{children}</Main>
124+
125+
<Spacer mb="5rem" />
126+
<Footer />
127+
</Flex>
128+
</Island>
129+
</Flex>
130+
131+
{hasRightSidebar && (
132+
<Box
133+
position="relative"
134+
width={`${rightWidth}px`}
135+
height="100%"
136+
flexShrink={0}
137+
>
138+
<ResizeHandle
139+
orientation="vertical"
140+
onResize={resizeRightSidebar}
141+
size={RESIZE_HANDLE_SIZE}
142+
gapSize={ISLAND_GAP}
143+
edge="left"
144+
invertDelta
145+
ariaLabel="Resize right sidebar"
146+
/>
147+
148+
<PageSidebar
149+
side="right"
150+
topContent={rightTopSidebarContent}
151+
bottomContent={rightBottomSidebarContent}
152+
width="100%"
153+
split={rightSplit}
154+
resizeHandleSize={RESIZE_HANDLE_SIZE}
155+
islandGap={ISLAND_GAP}
156+
onResizeSplit={resizeRightSidebarSplit}
157+
/>
158+
</Box>
159+
)}
105160
</Flex>
106-
107-
{hasRightSidebar && (
108-
<>
109-
<ResizeHandle
110-
orientation="vertical"
111-
onResize={resizeRightSidebar}
112-
size={RESIZE_HANDLE_SIZE}
113-
invertDelta
114-
ariaLabel="Resize right sidebar"
115-
/>
116-
117-
<PageSidebar
118-
side="right"
119-
topContent={rightTopSidebarContent}
120-
bottomContent={rightBottomSidebarContent}
121-
width={rightWidth}
122-
split={rightSplit}
123-
resizeHandleSize={RESIZE_HANDLE_SIZE}
124-
onResizeSplit={resizeRightSidebarSplit}
125-
/>
126-
</>
127-
)}
128161
</Flex>
129162
);
130163
}
@@ -136,14 +169,16 @@ function PageSidebar({
136169
width,
137170
split,
138171
resizeHandleSize,
172+
islandGap,
139173
onResizeSplit,
140174
}: PageSidebarProps) {
141175
const hasTopContent = hasContent(topContent);
142176
const hasBottomContent = hasContent(bottomContent);
177+
const sidebarWidth = typeof width === "number" ? `${width}px` : width;
143178

144179
if (!hasTopContent || !hasBottomContent) {
145180
return (
146-
<Sidebar width={`${width}px`}>
181+
<Sidebar width={sidebarWidth}>
147182
{hasTopContent ? topContent : bottomContent}
148183
</Sidebar>
149184
);
@@ -152,21 +187,24 @@ function PageSidebar({
152187
return (
153188
<Flex
154189
direction="column"
155-
width={`${width}px`}
190+
width={sidebarWidth}
156191
height="100%"
157192
flexShrink={0}
158193
overflow="hidden"
194+
gap={`${islandGap}px`}
159195
>
160-
<Flex minHeight={0} flexBasis={0} flexGrow={split} overflow="hidden">
196+
<Flex minHeight={0} flexBasis={0} flexGrow={split} position="relative">
161197
<Sidebar width="100%">{topContent}</Sidebar>
162-
</Flex>
163198

164-
<ResizeHandle
165-
orientation="horizontal"
166-
onResize={onResizeSplit}
167-
size={resizeHandleSize}
168-
ariaLabel={`Resize ${side} sidebar sections`}
169-
/>
199+
<ResizeHandle
200+
orientation="horizontal"
201+
onResize={onResizeSplit}
202+
size={resizeHandleSize}
203+
gapSize={islandGap}
204+
edge="bottom"
205+
ariaLabel={`Resize ${side} sidebar sections`}
206+
/>
207+
</Flex>
170208

171209
<Flex
172210
minHeight={0}

src/components/layout/page-layout/ResizeHandle.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ interface ResizeHandleProps {
55
orientation: "horizontal" | "vertical";
66
onResize: (delta: number) => void;
77
size: number;
8+
gapSize: number;
9+
edge: "left" | "right" | "bottom";
810
invertDelta?: boolean;
911
ariaLabel: string;
1012
}
@@ -13,6 +15,8 @@ export function ResizeHandle({
1315
orientation,
1416
onResize,
1517
size,
18+
gapSize,
19+
edge,
1620
invertDelta = false,
1721
ariaLabel,
1822
}: ResizeHandleProps) {
@@ -53,14 +57,27 @@ export function ResizeHandle({
5357
document.body.style.userSelect = "";
5458
};
5559

60+
const overlayOffset = `-${(size + gapSize) / 2}px`;
61+
5662
return (
5763
<Flex
5864
role="separator"
5965
aria-orientation={orientation}
6066
aria-label={ariaLabel}
6167
width={orientation === "vertical" ? `${size}px` : "100%"}
6268
height={orientation === "horizontal" ? `${size}px` : "100%"}
63-
flexShrink={0}
69+
position="absolute"
70+
top={orientation === "vertical" ? 0 : undefined}
71+
left={
72+
orientation === "horizontal"
73+
? 0
74+
: edge === "left"
75+
? overlayOffset
76+
: undefined
77+
}
78+
right={edge === "right" ? overlayOffset : undefined}
79+
bottom={edge === "bottom" ? overlayOffset : undefined}
80+
zIndex={1}
6481
cursor={cursor}
6582
bg="transparent"
6683
onPointerDown={handlePointerDown}

src/components/layout/page-layout/useResize.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const DEFAULT_SIDEBAR_SPLIT = 50;
55
const MIN_SIDEBAR_WIDTH = 300;
66
const MIN_MAIN_WIDTH = 320;
77

8-
const LAYOUT_PADDING = 8;
98
const RESIZE_HANDLE_SIZE = 8;
109

1110
const LEFT_WIDTH_STORAGE_KEY = "provideq.sidebar.left.width";
@@ -16,11 +15,13 @@ const RIGHT_SPLIT_STORAGE_KEY = "provideq.sidebar.right.split";
1615
interface UseResizeOptions {
1716
hasLeftSidebar: boolean;
1817
hasRightSidebar: boolean;
18+
islandGap: number;
1919
}
2020

2121
export function useResize({
2222
hasLeftSidebar,
2323
hasRightSidebar,
24+
islandGap,
2425
}: UseResizeOptions) {
2526
const [leftWidth, setLeftWidth] = useState(DEFAULT_SIDEBAR_WIDTH);
2627
const [rightWidth, setRightWidth] = useState(DEFAULT_SIDEBAR_WIDTH);
@@ -69,15 +70,13 @@ export function useResize({
6970
otherSidebarWidth: number,
7071
hasOtherSidebar: boolean,
7172
) => {
72-
const ownHandleWidth = RESIZE_HANDLE_SIZE;
73-
const otherSidebarAndHandleWidth = hasOtherSidebar
74-
? otherSidebarWidth + RESIZE_HANDLE_SIZE
75-
: 0;
73+
const sidebarGapCount = hasOtherSidebar ? 2 : 1;
74+
const otherSidebarWidthInLayout = hasOtherSidebar ? otherSidebarWidth : 0;
7675
const availableWidth =
7776
window.innerWidth -
78-
LAYOUT_PADDING * 2 -
79-
ownHandleWidth -
80-
otherSidebarAndHandleWidth -
77+
islandGap * 2 -
78+
islandGap * sidebarGapCount -
79+
otherSidebarWidthInLayout -
8180
MIN_MAIN_WIDTH;
8281

8382
return Math.max(MIN_SIDEBAR_WIDTH, availableWidth);
@@ -106,8 +105,7 @@ export function useResize({
106105
};
107106

108107
const getResizedSplit = (currentSplit: number, delta: number) => {
109-
const availableHeight =
110-
window.innerHeight - LAYOUT_PADDING * 2 - RESIZE_HANDLE_SIZE;
108+
const availableHeight = window.innerHeight - islandGap * 3;
111109

112110
if (availableHeight <= 0) {
113111
return currentSplit;
@@ -134,7 +132,6 @@ export function useResize({
134132
resizeLeftSidebarSplit,
135133
resizeRightSidebarSplit,
136134
MIN_MAIN_WIDTH,
137-
LAYOUT_PADDING,
138135
RESIZE_HANDLE_SIZE,
139136
};
140137
}

0 commit comments

Comments
 (0)