Restructure file system to seperate Sidebar, Header, and Canvas components

This commit is contained in:
Daniel S. Hansen
2025-07-21 11:33:44 -07:00
parent a7bef5ddb3
commit 06edb481e9
12 changed files with 15 additions and 13 deletions
@@ -0,0 +1,34 @@
import { Flex, HStack, chakra, useRecipe } from "@chakra-ui/react";
import { CanvasHeaderNav } from "./CanvasHeaderNav.jsx";
import { SearchBar } from "./SearchBar.jsx";
import { SettingsButton } from "./SettingsButton.jsx";
export default function CanvasHeader() {
const recipe = useRecipe({ key: "canvas" });
const styles = recipe();
return (
<chakra.div css={styles}>
<Flex
as="header"
position="sticky"
top="0"
// zIndex="banner"
bg="base200"
borderBottom="1px solid"
borderColor="gray.200"
px={6}
py={3}
align="center"
justify="space-between"
>
<CanvasHeaderNav />
<HStack spacing={3}>
<SearchBar />
<SettingsButton />
</HStack>
</Flex>
</chakra.div>
);
}
@@ -0,0 +1,22 @@
import { HStack, Link } from "@chakra-ui/react"
const navItems = [
{ label: "My Dashboard", href: "#dashboard" },
{ label: "Gas", href: "#gas" },
{ label: "Seismic", href: "#seismic" },
{ label: "Remote Sensing", href: "#remote" },
{ label: "Daily Activity", href: "#daily" },
];
export function CanvasHeaderNav() {
return (
<HStack as="nav" gap="8">
{navItems.map(({ label, href }) => (
<Link key={href} href={href} fontWeight="medium">
{label}
</Link>
))}
</HStack>
);
}
@@ -0,0 +1,16 @@
import { Input, InputGroup } from "@chakra-ui/react";
import { FiSearch } from "react-icons/fi"
export function SearchBar({ placeholder="Enter a volcano to search", size="sm", width="210px" }) {
return (
<InputGroup startElement={<FiSearch />}>
<Input
placeholder={placeholder}
size={size}
width={width}
borderRadius="full"
/>
</InputGroup>
);
}
@@ -0,0 +1,54 @@
// This component displays a drop down menu when clicked, with custom functionality
// for 'Add Widget', 'Edit Widgets', and 'Remove Widgets'. This component will
// control settings related to the Widgets on the main canvas.
import { Button, IconButton, Menu, Portal } from "@chakra-ui/react";
import { FiSettings } from "react-icons/fi";
export function SettingsButton(props) {
const handleAddWidget = () => {
console.log("Add Widget clicked");
// TODO: Implement widget-adding logic
}
const handleEditWidgdets = () => {
console.log("Edit Widgets clicked")
// TODO: Implement widget-editing logic
}
const handleDeleteWidgets = () => {
console.log("Delete Widgets clicked");
// TODO: Implement widget-deletion logic
}
return (
// This uses Chakra's built in menu component
<Menu.Root>
<Menu.Trigger asChild>
<IconButton variant="ghost" size="md">
<FiSettings />
</IconButton>
</Menu.Trigger>
<Portal>
<Menu.Positioner>
<Menu.Content>
<Menu.Item onClick={handleAddWidget} value="addwidget">Add Widget</Menu.Item>
<Menu.Item onClick={handleEditWidgdets} value ="editwidget">Edit Widgets</Menu.Item>
<Menu.Item
onClick={handleDeleteWidgets}
color="fg.error"
_hover={{ bg: "bg.error", color: "fg.error "}}
>
Delete Widgets
</Menu.Item>
</Menu.Content>
</Menu.Positioner>
</Portal>
</Menu.Root>
);
}
@@ -0,0 +1,57 @@
// 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 from 'react-grid-layout';
export default function Widget() {
// Define widgets initial position and size
// TODO Add dynamic adding/deleting of widgets via options button
const [layout, setLayout] = useState([
{ i: 'myWidget1', x: 0, y: 0, w: 3, h: 3, minH: 3, static: false },
{ i: 'myWidget2', x: 3, y: 0, w: 3, h: 3, minH: 3, static: false },
{ i: 'myWidget3', x: 6, y: 0, w: 3, h: 3, minH: 3, static: false }
]);
const onLayoutChange = (newLayout) => {
setLayout(newLayout);
console.log('Updated layout:', newLayout)
};
return (
<GridLayout
className="layout"
layout={layout}
cols={12} // Total columns in grid
rowHeight={30} //Height of a single row in px
width={1200} // Total width of the grid
margin={[10, 10]} // [horizontal, vertical] gap
onLayoutChange={onLayoutChange}
draggableHandle=".widget-handle" // Make only the header draggable
>
<div key="myWidget1" style={{ background: '#f0f0f0', borderRadius: 4 }}>
<div className="widget-handle" style={{ padding: '4px', cursor: 'move', background: '#ddd' }}>
VDAP Widget
</div>
<div style={{ padding: '8px' }}>
This is the widget content - drag or resize me!
</div>
</div><div key="myWidget2" style={{ background: '#f0f0f0', borderRadius: 4 }}>
<div className="widget-handle" style={{ padding: '4px', cursor: 'move', background: '#ddd' }}>
VDAP Widget
</div>
<div style={{ padding: '8px' }}>
This is the widget content - drag or resize me!
</div>
</div><div key="myWidget3" style={{ background: '#f0f0f0', borderRadius: 4 }}>
<div className="widget-handle" style={{ padding: '4px', cursor: 'move', background: '#ddd' }}>
VDAP Widget
</div>
<div style={{ padding: '8px' }}>
This is the widget content - drag or resize me!
</div>
</div>
</GridLayout>
);
}