added submenu to settings

widget information is now stored in two arrays. One array (widgetArray) holds the id and name/type of the widget. The second array (layout) holds the id, position, width, height, and static info
This commit is contained in:
2025-08-04 12:04:33 -07:00
parent 90704879e1
commit 1f83dcf9bb
9 changed files with 158 additions and 102 deletions
@@ -14,22 +14,21 @@ import DeleteAllButton from "../components/DeleteAllButton";
export function DashboardCanvas({ view, setView, layout, setLayout, onLayoutChange }) {
const [isEditable, setIsEditable] = useState(false); // editable=true means static=false (vice versa)
const [isDelete, setIsDelete] = useState(false);
const [newCounter, setNewCounter] = useState(3);
const [originalLayout, setOriginalLayout] = useState([]);
const [widgetArray, setWidgetArray] = useState([]);
const onAddWidget = () => {
const newId = newCounter.toString();
const onAddWidget = (ID) => {
setLayout(prev => [
...prev,
{
i: newId,
x: (prev.length * 3) % 12,
y: Infinity,
w: 3,
h: 3,
}
...prev,
{
i: ID,
x: (prev.length * 3) % 12,
y: Infinity,
w: 3,
h: 3,
static: false
}
]);
setNewCounter(prev => prev + 1);
};
useEffect(() => {
@@ -78,6 +77,7 @@ export function DashboardCanvas({ view, setView, layout, setLayout, onLayoutChan
const DeleteWidget = (id) => {
console.log("Deleting widget with id: ", id);
setLayout(layout => layout.filter(w => w.i !== id));
// add removal for widgetArray here
}
const DeleteAll = () => {
@@ -86,6 +86,7 @@ export function DashboardCanvas({ view, setView, layout, setLayout, onLayoutChan
);
if (confirm) {
setLayout([]);
setWidgetArray([]);
onSave();
}
else return;
@@ -157,6 +158,8 @@ export function DashboardCanvas({ view, setView, layout, setLayout, onLayoutChan
onAddWidget={ onAddWidget }
onEditWidgets={ onEditWidgets }
onDeleteWidgets={ onDeleteWidgets }
setWidgetArray={ setWidgetArray }
widgetArray={ widgetArray }
/>
</>
)}
@@ -166,11 +169,13 @@ export function DashboardCanvas({ view, setView, layout, setLayout, onLayoutChan
{/* CANVAS */}
<Tabs.Content value="widget">
<WidgetCanvas
layout={layout}
onLayoutChange={onLayoutChange}
isEditable={isEditable}
isDelete={isDelete}
DeleteWidget={DeleteWidget}
layout={ layout }
onLayoutChange={ onLayoutChange }
isEditable={ isEditable }
isDelete={ isDelete }
DeleteWidget={ DeleteWidget }
setWidgetArray={ setWidgetArray }
widgetArray={ widgetArray }
/>
</Tabs.Content>
<Tabs.Content value="gas">
@@ -1,50 +1,50 @@
// This component defines a generic Widget that can be dynamically resized and
// dragged inside the canvas
// Content not included, must be populated using custom charts plots and notifications
import { useState } from 'react';
import GridLayout, { WidthProvider } from 'react-grid-layout';
import Widget from '../../components/Widget.jsx';
import { useSlotRecipe, chakra, Flex } from '@chakra-ui/react';
export default function WidgetCanvas({layout, onLayoutChange, isEditable, isDelete, DeleteWidget}) {
export default function WidgetCanvas({layout, onLayoutChange, isEditable, isDelete, DeleteWidget, widgetArray}) {
console.log("rendering widgetcanvas");
// Define widgets initial position and size
// TODO Add dynamic adding/deleting of widgets via options button
const recipe = useSlotRecipe({ key: "widget" });
const styles = recipe(); // using root recipe for widget below
const ResponsiveGridLayout = WidthProvider(GridLayout); // canvas width now adjusts to window size
const recipe = useSlotRecipe({ key: "widget" });
const styles = recipe(); // using root recipe for widget below
const ResponsiveGridLayout = WidthProvider(GridLayout); // canvas width now adjusts to window size
const handleDragStart = () => { document.body.style.userSelect = "none"; }; // don't allow text highlighting when dragging
const handleDragStop = () => { document.body.style.userSelect = ""; }; // allow text highlighting all other times
let merged = [];
// don't allow text highlighting when dragging
const handleDragStart = () => {
document.body.style.userSelect = "none";
};
// allow text highlighting all other times
const handleDragStop = () => {
document.body.style.userSelect = "";
};
console.log("widgetArray: ", widgetArray);
console.log("layout: ", layout);
if (widgetArray.length && layout.length) {
const widgetMap = new Map(widgetArray.map(item => [item.i, item]));
merged = layout.map(item => {
return {
...item,
...widgetMap.get(item.i)
};
});
};
return (
<chakra.div width="100%">
<ResponsiveGridLayout
className="layout"
layout={layout}
cols={12} // Total columns in grid
rowHeight={30} //Height of a single row in px
isBounded={true} // Total width of the grid
margin={[10, 10]} // [horizontal, vertical] gap
onLayoutChange={onLayoutChange}
draggableHandle=".widget-handle" // Make only the header draggable
onDragStart={handleDragStart}
onDragStop={handleDragStop}
>
{layout.map((item) => (
// this flex wrapper allows the widget to shrink down to the header size, no less
<Flex key={item.i} css={styles.root} height="100%" >
<Widget id={item.i} title="VDAP Widget" isEditable={isEditable} isDelete={isDelete} DeleteWidget={DeleteWidget}/>
</Flex>
))}
</ResponsiveGridLayout>
return (
<chakra.div width="100%">
<ResponsiveGridLayout
className="layout"
layout={layout}
cols={12} // Total columns in grid
rowHeight={30} //Height of a single row in px
isBounded={true} // Total width of the grid
margin={[10, 10]} // [horizontal, vertical] gap
onLayoutChange={onLayoutChange}
draggableHandle=".widget-handle" // Make only the header draggable
onDragStart={handleDragStart}
onDragStop={handleDragStop}
>
{merged.map((item) => {
const Widget = item.widget;
return (
<Flex key={item.i} css={styles.root} height="100%" >
<Widget id={item.i} isEditable={isEditable} isDelete={isDelete} DeleteWidget={DeleteWidget}/>
</Flex>
)
})}
</ResponsiveGridLayout>
</chakra.div>
);
}