From 906acb5c4c2c427a598cf04070ef683780377e11 Mon Sep 17 00:00:00 2001 From: Chris Lewis Date: Sun, 6 Oct 2024 16:15:59 +0100 Subject: [PATCH] Sidebar --- dashboard2/src/components/AppArea.ts | 7 +++--- dashboard2/src/components/DeviceRow.ts | 31 ++++++++++++++----------- dashboard2/src/components/IconButton.ts | 24 +++++++++++++++++++ dashboard2/src/components/SideBar.ts | 23 +++++++++++++++--- dashboard2/src/index.ts | 3 +++ 5 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 dashboard2/src/components/IconButton.ts diff --git a/dashboard2/src/components/AppArea.ts b/dashboard2/src/components/AppArea.ts index befe448..0225901 100644 --- a/dashboard2/src/components/AppArea.ts +++ b/dashboard2/src/components/AppArea.ts @@ -22,14 +22,15 @@ const NoDeviceLabel = () => fabricate('Text') * @returns {HTMLElement} Fabricate component. */ const AppArea = () => fabricate('Row') - .setStyles({ - width: '100%', - }) + .setStyles({ width: '100%' }) .onUpdate(async (el, state) => { const { selectedDevice } = state; if (!selectedDevice) { el.setChildren([NoDeviceLabel()]); + } else { + setTimeout(() => el.scrollIntoView({ behavior: 'smooth' }), 200); + el.setChildren([fabricate('Text').setText(JSON.stringify(selectedDevice))]) } }, [fabricate.StateKeys.Created, 'selectedDevice']); diff --git a/dashboard2/src/components/DeviceRow.ts b/dashboard2/src/components/DeviceRow.ts index 1eafe40..aa73edb 100644 --- a/dashboard2/src/components/DeviceRow.ts +++ b/dashboard2/src/components/DeviceRow.ts @@ -12,39 +12,42 @@ declare const fabricate: Fabricate; * @returns {HTMLElement} Fabricate component. */ const DeviceRow = ({ device }: { device: Device }) => { - const { deviceType, deviceName } = device; + const { deviceType, deviceName, localIp } = device; const nameView = fabricate('Text') - .setStyles(({ fonts }) => ({ + .setStyles({ color: 'white', - fontSize: '1.2rem', - fontFamily: fonts.code, + fontSize: '1.1rem', fontWeight: 'bold', - })) + }) .setText(deviceName); + const localIpView = fabricate('Text') + .setStyles(({ fonts, palette }) => ({ + color: palette.greyC, + fontSize: '1rem', + fontFamily: fonts.code, + })) + .setText(localIp); return fabricate('Row') .setStyles(({ palette }) => ({ - backgroundColor: palette.grey2, - padding: '8px 0px 8px 5px', + backgroundColor: palette.grey3, + padding: '4px 0px 4px 5px', cursor: 'pointer', - minWidth: '240px', })) .setChildren([ fabricate('Image', { src: `assets/images/${ICON_NAMES[deviceType]}.png` }) .setStyles({ width: '32px', height: '32px' }), fabricate('Column') - .setChildren([ - nameView, - ]), + .setChildren([nameView, localIpView]), ]) .onHover((el, state, isHovered) => { el.setStyles(({ palette }) => ({ - backgroundColor: isHovered ? palette.grey3 : palette.grey2, + backgroundColor: isHovered ? palette.grey4 : palette.grey3, })); }) - .onClick((el, state) => { - // Show apps for device + .onClick(() => { + fabricate.update({ selectedDevice: device }); }); }; diff --git a/dashboard2/src/components/IconButton.ts b/dashboard2/src/components/IconButton.ts new file mode 100644 index 0000000..9d92366 --- /dev/null +++ b/dashboard2/src/components/IconButton.ts @@ -0,0 +1,24 @@ +import { Fabricate, FabricateComponent } from 'fabricate.js'; +import { AppState } from '../types'; + +declare const fabricate: Fabricate; + +/** + * IconButton component. + * + * @param {object} props - Component props. + * @param {string} props.src - Icon src. + * @returns {FabricateComponent} IconButton component. + */ +const IconButton = ({ src }: { src: string }) => fabricate('Image', { src }) + .setStyles(({ palette }) => ({ + width: '26px', + height: '26px', + backgroundColor: palette.grey3, + padding: '3px', + borderRadius: '3px', + marginRight: '5px', + cursor: 'pointer', + })); + +export default IconButton; diff --git a/dashboard2/src/components/SideBar.ts b/dashboard2/src/components/SideBar.ts index 83e9ecf..7e8f5ee 100644 --- a/dashboard2/src/components/SideBar.ts +++ b/dashboard2/src/components/SideBar.ts @@ -18,7 +18,10 @@ const GroupLabel = ({ publicIp }: { publicIp: string }) => fabricate('Text') fontSize: '1rem', fontFamily: fonts.code, fontWeight: 'bold', - margin: '15px auto 8px auto', + padding: '15px 0px 8px 5px', + textAlign: 'center', + backgroundColor: palette.grey2, + margin: '0px', })) .setText(publicIp); @@ -29,12 +32,25 @@ const GroupLabel = ({ publicIp }: { publicIp: string }) => fabricate('Text') */ const SideBar = () => fabricate('Column') .setStyles(({ palette }) => ({ - backgroundColor: palette.grey2, - height: '95vh', + backgroundColor: palette.grey3, + minWidth: '240px', })) + .setNarrowStyles({ width: '100vw' }) .onUpdate(async (el, state) => { const { fleet } = state; + if (!fleet.length) { + el.setChildren([ + fabricate('Loader', { + size: 48, + color: 'white', + backgroundColor: '#0000', + }) + .setStyles({ margin: '10px auto' }), + ]); + return; + } + // Sort fleet into publicIp buckets const buckets: Record = {}; fleet.forEach((device) => { @@ -47,6 +63,7 @@ const SideBar = () => fabricate('Column') }); // Group area for each bucket + el.empty(); Object .entries(buckets) .forEach(([publicIp, devices]) => { diff --git a/dashboard2/src/index.ts b/dashboard2/src/index.ts index 1768e45..01f9dbd 100644 --- a/dashboard2/src/index.ts +++ b/dashboard2/src/index.ts @@ -24,9 +24,12 @@ const AppNavBar = () => fabricate('NavBar', { * @returns {HTMLElement} Fabricate component. */ const App = () => fabricate('Column') + .setStyles({ height: '100vh' }) .setChildren([ AppNavBar(), fabricate('Row') + .setStyles({ height: '100vh' }) + .setNarrowStyles({ flexWrap: 'wrap' }) .setChildren([ SideBar(), AppArea(),