mirror of
https://github.com/maputnik/editor.git
synced 2026-10-28 13:53:44 +00:00
- Replaces #1870, which replaced #1682, #1677 This mostly uses the code from there and addresses the comments I've left. I didn't change the code much. ## Launch Checklist Makes the sidebar panel resizable <img width="707" height="511" alt="image" src="https://github.com/user-attachments/assets/d010df38-faac-441c-bf7f-a4960e471c61" /> - [x] Briefly describe the changes in this PR. - [x] Link to related issues. - [x] Include before/after visuals or gifs if this PR includes visual changes. - [x] Write tests for all new functionality. - [x] Add an entry to `CHANGELOG.md` under the `## main` section. --------- Co-authored-by: Bart Louwers <bart.louwers@gmail.com>
132 lines
4.5 KiB
TypeScript
132 lines
4.5 KiB
TypeScript
import React, { useEffect, useState } from "react";
|
|
import { Group, Panel, Separator, useDefaultLayout } from "react-resizable-panels";
|
|
import { ScrollContainer } from "./ScrollContainer";
|
|
import { useTranslation } from "react-i18next";
|
|
import { IconContext } from "react-icons";
|
|
|
|
const DEFAULT_LIST_WIDTH = 200;
|
|
const DEFAULT_DRAWER_WIDTH = 370;
|
|
const DEFAULT_SIDEBAR_WIDTH = DEFAULT_LIST_WIDTH + DEFAULT_DRAWER_WIDTH;
|
|
const PANEL_STYLE: React.CSSProperties = { overflow: "hidden" };
|
|
|
|
const SIDEBAR_LAYOUT_ID = "maputnik:sidebar-layout";
|
|
const SIDEBAR_INNER_LAYOUT_ID = "maputnik:sidebar-inner-layout";
|
|
const SIDEBAR_PANEL_ID = "sidebar";
|
|
const MAP_PANEL_ID = "map";
|
|
const LIST_PANEL_ID = "list";
|
|
const DRAWER_PANEL_ID = "drawer";
|
|
|
|
type AppLayoutProps = {
|
|
toolbar: React.ReactElement
|
|
layerList: React.ReactElement
|
|
layerEditor?: React.ReactElement
|
|
codeEditor?: React.ReactElement
|
|
map: React.ReactElement
|
|
bottom?: React.ReactElement
|
|
modals?: React.ReactNode
|
|
};
|
|
|
|
export const AppLayout: React.FC<AppLayoutProps> = (props) => {
|
|
const { t, i18n } = useTranslation();
|
|
|
|
const sidebarLayout = useDefaultLayout({
|
|
id: SIDEBAR_LAYOUT_ID,
|
|
panelIds: [SIDEBAR_PANEL_ID, MAP_PANEL_ID],
|
|
});
|
|
const innerLayout = useDefaultLayout({
|
|
id: SIDEBAR_INNER_LAYOUT_ID,
|
|
panelIds: [LIST_PANEL_ID, DRAWER_PANEL_ID],
|
|
});
|
|
|
|
// The bottom panel is position: fixed, so it can't be a flex sibling of the
|
|
// map panel; it follows the sidebar through this custom property instead.
|
|
const [sidebarWidth, setSidebarWidth] = useState(DEFAULT_SIDEBAR_WIDTH);
|
|
|
|
useEffect(() => {
|
|
document.body.dir = i18n.dir();
|
|
}, [i18n, i18n.language]);
|
|
|
|
return <IconContext.Provider value={{size: "14px"}}>
|
|
<div
|
|
className="maputnik-layout"
|
|
style={{"--sidebar-width": `${sidebarWidth}px`} as React.CSSProperties}
|
|
>
|
|
{props.toolbar}
|
|
<div className="maputnik-layout-main">
|
|
<Group
|
|
className="maputnik-layout-panels"
|
|
orientation="horizontal"
|
|
id={SIDEBAR_LAYOUT_ID}
|
|
defaultLayout={sidebarLayout.defaultLayout}
|
|
onLayoutChanged={sidebarLayout.onLayoutChanged}
|
|
>
|
|
<Panel
|
|
id={SIDEBAR_PANEL_ID}
|
|
data-wd-key="sidebar-panel"
|
|
className={props.codeEditor ? "maputnik-layout-code-editor" : "maputnik-layout-sidebar"}
|
|
style={PANEL_STYLE}
|
|
defaultSize={`${DEFAULT_SIDEBAR_WIDTH}px`}
|
|
minSize="280px"
|
|
onResize={({inPixels}) => setSidebarWidth(inPixels)}
|
|
>
|
|
{props.codeEditor && <ScrollContainer>
|
|
{props.codeEditor}
|
|
</ScrollContainer>
|
|
}
|
|
{!props.codeEditor && <Group
|
|
className="maputnik-layout-sidebar-panels"
|
|
orientation="horizontal"
|
|
id={SIDEBAR_INNER_LAYOUT_ID}
|
|
defaultLayout={innerLayout.defaultLayout}
|
|
onLayoutChanged={innerLayout.onLayoutChanged}
|
|
>
|
|
<Panel
|
|
id={LIST_PANEL_ID}
|
|
data-wd-key="layer-list-panel"
|
|
className="maputnik-layout-list"
|
|
style={PANEL_STYLE}
|
|
defaultSize={`${DEFAULT_LIST_WIDTH}px`}
|
|
minSize="100px"
|
|
>
|
|
{props.layerList}
|
|
</Panel>
|
|
<Separator
|
|
className="maputnik-layout-resize-handle"
|
|
data-wd-key="inner-resize-handle"
|
|
title={t("Drag to resize the layer list")}
|
|
aria-label={t("Drag to resize the layer list")}
|
|
/>
|
|
<Panel
|
|
id={DRAWER_PANEL_ID}
|
|
className="maputnik-layout-drawer"
|
|
style={PANEL_STYLE}
|
|
defaultSize={`${DEFAULT_DRAWER_WIDTH}px`}
|
|
minSize="150px"
|
|
>
|
|
<ScrollContainer>
|
|
{props.layerEditor}
|
|
</ScrollContainer>
|
|
</Panel>
|
|
</Group>
|
|
}
|
|
</Panel>
|
|
<Separator
|
|
className="maputnik-layout-resize-handle"
|
|
data-wd-key="sidebar-resize-handle"
|
|
title={t("Drag to resize the sidebar")}
|
|
aria-label={t("Drag to resize the sidebar")}
|
|
/>
|
|
<Panel id={MAP_PANEL_ID} className="maputnik-layout-map" style={PANEL_STYLE} minSize="200px">
|
|
{props.map}
|
|
</Panel>
|
|
</Group>
|
|
</div>
|
|
{props.bottom && <div className="maputnik-layout-bottom">
|
|
{props.bottom}
|
|
</div>
|
|
}
|
|
{props.modals}
|
|
</div>
|
|
</IconContext.Provider>;
|
|
};
|