2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-17 04:25:42 +00:00
Files
InvenTree/src/frontend/src/components/widgets/WidgetLayout.tsx
Matthias Mair dc58198488 More style fixes (#8140)
* more style fixes

* fix more changes
2024-09-18 09:15:47 +10:00

233 lines
5.2 KiB
TypeScript

import { Trans } from '@lingui/macro';
import {
ActionIcon,
Container,
Group,
Indicator,
Menu,
Text
} from '@mantine/core';
import { useDisclosure, useHotkeys } from '@mantine/hooks';
import {
IconArrowBackUpDouble,
IconDotsVertical,
IconLayout2,
IconSquare,
IconSquareCheck
} from '@tabler/icons-react';
import { useEffect, useState } from 'react';
import { Responsive, WidthProvider } from 'react-grid-layout';
import * as classes from './WidgetLayout.css';
const ReactGridLayout = WidthProvider(Responsive);
interface LayoutStorage {
[key: string]: {};
}
const compactType = 'vertical';
export interface LayoutItemType {
i: number;
val: string | JSX.Element | JSX.Element[] | (() => JSX.Element);
w?: number;
h?: number;
x?: number;
y?: number;
minH?: number;
}
export function WidgetLayout({
items = [],
className = 'layout',
localstorageName = 'argl',
rowHeight = 30
}: Readonly<{
items: LayoutItemType[];
className?: string;
localstorageName?: string;
rowHeight?: number;
}>) {
const [layouts, setLayouts] = useState({});
const [editable, setEditable] = useDisclosure(false);
const [boxShown, setBoxShown] = useDisclosure(true);
useEffect(() => {
let layout = getFromLS('layouts') || [];
const new_layout = JSON.parse(JSON.stringify(layout));
setLayouts(new_layout);
}, []);
function getFromLS(key: string) {
let ls: LayoutStorage = {};
if (localStorage) {
try {
ls = JSON.parse(localStorage.getItem(localstorageName) || '') || {};
} catch (e) {
/*Ignore*/
}
}
return ls[key];
}
function saveToLS(key: string, value: any) {
if (localStorage) {
localStorage.setItem(
localstorageName,
JSON.stringify({
[key]: value
})
);
}
}
function resetLayout() {
setLayouts({});
}
function onLayoutChange(layout: any, layouts: any) {
saveToLS('layouts', layouts);
setLayouts(layouts);
}
return (
<div>
<WidgetControlBar
editable={editable}
editFnc={setEditable.toggle}
resetLayout={resetLayout}
boxShown={boxShown}
boxFnc={setBoxShown.toggle}
/>
{layouts ? (
<ReactGridLayout
className={className}
cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
rowHeight={rowHeight}
layouts={layouts}
onLayoutChange={(layout, layouts) => onLayoutChange(layout, layouts)}
compactType={compactType}
isDraggable={editable}
isResizable={editable}
>
{items.map((item) => {
return LayoutItem(item, boxShown, classes);
})}
</ReactGridLayout>
) : (
<div>
<Trans>Loading</Trans>
</div>
)}
</div>
);
}
function WidgetControlBar({
editable,
editFnc,
resetLayout,
boxShown,
boxFnc
}: Readonly<{
editable: boolean;
editFnc: () => void;
resetLayout: () => void;
boxShown: boolean;
boxFnc: () => void;
}>) {
useHotkeys([['mod+E', () => editFnc()]]);
return (
<Group justify="right">
<Menu
shadow="md"
width={200}
openDelay={100}
closeDelay={400}
position="bottom-end"
>
<Menu.Target>
<Indicator
color="red"
position="bottom-start"
processing
disabled={!editable}
>
<ActionIcon variant="transparent">
<IconDotsVertical />
</ActionIcon>
</Indicator>
</Menu.Target>
<Menu.Dropdown>
<Menu.Label>
<Trans>Layout</Trans>
</Menu.Label>
<Menu.Item
leftSection={<IconArrowBackUpDouble size={14} />}
onClick={resetLayout}
>
<Trans>Reset Layout</Trans>
</Menu.Item>
<Menu.Item
leftSection={
<IconLayout2 size={14} color={editable ? 'red' : undefined} />
}
onClick={editFnc}
rightSection={
<Text size="xs" c="dimmed">
E
</Text>
}
>
{editable ? <Trans>Stop Edit</Trans> : <Trans>Edit Layout</Trans>}
</Menu.Item>
<Menu.Divider />
<Menu.Label>
<Trans>Appearance</Trans>
</Menu.Label>
<Menu.Item
leftSection={
boxShown ? (
<IconSquareCheck size={14} />
) : (
<IconSquare size={14} />
)
}
onClick={boxFnc}
>
<Trans>Show Boxes</Trans>
</Menu.Item>
</Menu.Dropdown>
</Menu>
</Group>
);
}
function LayoutItem(
item: any,
backgroundColor: boolean,
classes: { backgroundItem: string; baseItem: string }
) {
return (
<Container
key={item.i}
data-grid={{
w: item.w || 3,
h: item.h || 3,
x: item.x || 0,
y: item.y || 0,
minH: item.minH || undefined,
minW: item.minW || undefined
}}
className={backgroundColor ? classes.backgroundItem : classes.baseItem}
>
{item.val}
</Container>
);
}