From d26128af0ef96d46380b9564415b6d8465a1ce8f Mon Sep 17 00:00:00 2001 From: Meierschlumpf Date: Fri, 6 Jan 2023 23:50:08 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Sidebars=20not=20working?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/configs/default.json | 548 +++++++++--------- .../Ribbon/MobileRibbonSidebarDrawer.tsx | 2 +- .../Dashboard/Views/DashboardView.tsx | 9 +- .../Dashboard/Wrappers/Sidebar/Sidebar.tsx | 45 +- .../Wrappers/gridstack/init-gridstack.ts | 20 +- .../Wrappers/gridstack/use-gridstack.ts | 1 + src/hooks/use-resize.ts | 15 +- src/styles/global.scss | 36 +- 8 files changed, 366 insertions(+), 310 deletions(-) diff --git a/data/configs/default.json b/data/configs/default.json index d4f9186a6..07fe28621 100644 --- a/data/configs/default.json +++ b/data/configs/default.json @@ -18,8 +18,69 @@ ], "apps": [ { - "id": "76217a87-7151-42d0-b0cf-1b72aef63f83", - "name": "Small app", + "id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33a", + "name": "Documentation", + "url": "https://homarr.dev", + "behaviour": { + "onClickUrl": "https://homarr.dev", + "externalUrl": "https://homarr.dev", + "isOpeningNewTab": true + }, + "network": { + "enabledStatusChecker": false, + "okStatus": [ + 200 + ] + }, + "appearance": { + "iconUrl": "/imgs/logo/logo.png" + }, + "integration": { + "type": null, + "properties": [] + }, + "area": { + "type": "category", + "properties": { + "id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f" + } + }, + "shape": { + "md": { + "location": { + "x": 0, + "y": 10 + }, + "size": { + "width": 1, + "height": 1 + } + }, + "sm": { + "location": { + "x": 0, + "y": 10 + }, + "size": { + "width": 2, + "height": 1 + } + }, + "lg": { + "location": { + "x": 3, + "y": 1 + }, + "size": { + "width": 1, + "height": 1 + } + } + } + }, + { + "id": "5df743d9-5cb1-457c-85d2-64ff86855652", + "name": "Your app", "url": "https://homarr.dev", "appearance": { "iconUrl": "/imgs/logo/logo.png" @@ -41,7 +102,7 @@ "shape": { "md": { "location": { - "x": 1, + "x": 5, "y": 1 }, "size": { @@ -51,8 +112,8 @@ }, "sm": { "location": { - "x": 0, - "y": 3 + "x": 2, + "y": 0 }, "size": { "width": 1, @@ -61,7 +122,187 @@ }, "lg": { "location": { - "x": 4, + "x": 1, + "y": 0 + }, + "size": { + "width": 1, + "height": 1 + } + } + }, + "integration": { + "type": null, + "properties": [] + } + }, + { + "id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a990", + "name": "Donate", + "url": "https://ko-fi.com/ajnart", + "behaviour": { + "onClickUrl": "https://ko-fi.com/ajnart", + "externalUrl": "https://ko-fi.com/ajnart", + "isOpeningNewTab": true + }, + "network": { + "enabledStatusChecker": false, + "okStatus": [ + 200 + ] + }, + "appearance": { + "iconUrl": "https://uploads-ssl.webflow.com/5c14e387dab576fe667689cf/61e1116779fc0a9bd5bdbcc7_Frame%206.png" + }, + "integration": { + "type": null, + "properties": [] + }, + "area": { + "type": "sidebar", + "properties": { + "location": "left" + } + }, + "shape": { + "md": { + "location": { + "x": 1, + "y": 0 + }, + "size": { + "width": 1, + "height": 1 + } + }, + "sm": { + "location": { + "x": 1, + "y": 0 + }, + "size": { + "width": 1, + "height": 1 + } + }, + "lg": { + "location": { + "x": 1, + "y": 0 + }, + "size": { + "width": 1, + "height": 1 + } + } + } + }, + { + "id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a330", + "name": "Contribute", + "url": "https://github.com/ajnart/homarr", + "behaviour": { + "onClickUrl": "https://github.com/ajnart/homarr", + "externalUrl": "https://github.com/ajnart/homarr", + "isOpeningNewTab": true + }, + "network": { + "enabledStatusChecker": false, + "okStatus": [ + 200 + ] + }, + "appearance": { + "iconUrl": "https://cdn.jsdelivr.net/gh/walkxhub/dashboard-icons/png/github.png" + }, + "integration": { + "type": null, + "properties": [] + }, + "area": { + "type": "category", + "properties": { + "id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f" + } + }, + "shape": { + "md": { + "location": { + "x": 5, + "y": 3 + }, + "size": { + "width": 1, + "height": 1 + } + }, + "sm": { + "location": { + "x": 0, + "y": 2 + }, + "size": { + "width": 1, + "height": 1 + } + }, + "lg": { + "location": { + "x": 2, + "y": 1 + }, + "size": { + "width": 1, + "height": 1 + } + } + } + }, + { + "id": "76217a87-7151-42d0-b0cf-1b72aef63f83", + "name": "Small app", + "url": "https://homarr.dev", + "appearance": { + "iconUrl": "/imgs/logo/logo.png" + }, + "network": { + "enabledStatusChecker": false, + "okStatus": [] + }, + "behaviour": { + "isOpeningNewTab": true, + "externalUrl": "https://homarr.dev" + }, + "area": { + "type": "sidebar", + "properties": { + "location": "left" + } + }, + "shape": { + "md": { + "location": { + "x": 0, + "y": 0 + }, + "size": { + "width": 1, + "height": 1 + } + }, + "sm": { + "location": { + "x": 0, + "y": 0 + }, + "size": { + "width": 1, + "height": 1 + } + }, + "lg": { + "location": { + "x": 0, "y": 0 }, "size": { @@ -105,6 +346,16 @@ }, "shape": { "md": { + "location": { + "x": 0, + "y": 0 + }, + "size": { + "width": 1, + "height": 4 + } + }, + "sm": { "location": { "x": 0, "y": 1 @@ -114,208 +365,15 @@ "height": 1 } }, - "sm": { - "location": { - "x": 1, - "y": 2 - }, - "size": { - "width": 1, - "height": 1 - } - }, "lg": { "location": { "x": 0, "y": 0 }, - "size": { - "width": 4, - "height": 3 - } - } - } - }, - { - "id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a330", - "name": "Contribute", - "url": "https://github.com/ajnart/homarr", - "behaviour": { - "onClickUrl": "https://github.com/ajnart/homarr", - "externalUrl": "https://github.com/ajnart/homarr", - "isOpeningNewTab": true - }, - "network": { - "enabledStatusChecker": false, - "okStatus": [ - 200 - ] - }, - "appearance": { - "iconUrl": "https://cdn.jsdelivr.net/gh/walkxhub/dashboard-icons/png/github.png" - }, - "integration": { - "type": null, - "properties": [] - }, - "area": { - "type": "category", - "properties": { - "id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f" - } - }, - "shape": { - "md": { - "location": { - "x": 3, - "y": 1 - }, "size": { "width": 1, "height": 1 } - }, - "sm": { - "location": { - "x": 1, - "y": 4 - }, - "size": { - "width": 1, - "height": 1 - } - }, - "lg": { - "location": { - "x": 4, - "y": 2 - }, - "size": { - "width": 1, - "height": 1 - } - } - } - }, - { - "id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a990", - "name": "Donate", - "url": "https://ko-fi.com/ajnart", - "behaviour": { - "onClickUrl": "https://ko-fi.com/ajnart", - "externalUrl": "https://ko-fi.com/ajnart", - "isOpeningNewTab": true - }, - "network": { - "enabledStatusChecker": false, - "okStatus": [ - 200 - ] - }, - "appearance": { - "iconUrl": "https://uploads-ssl.webflow.com/5c14e387dab576fe667689cf/61e1116779fc0a9bd5bdbcc7_Frame%206.png" - }, - "integration": { - "type": null, - "properties": [] - }, - "area": { - "type": "category", - "properties": { - "id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f" - } - }, - "shape": { - "md": { - "location": { - "x": 2, - "y": 0 - }, - "size": { - "width": 1, - "height": 1 - } - }, - "sm": { - "location": { - "x": 2, - "y": 0 - }, - "size": { - "width": 1, - "height": 1 - } - }, - "lg": { - "location": { - "x": 5, - "y": 0 - }, - "size": { - "width": 1, - "height": 1 - } - } - } - }, - { - "id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33a", - "name": "Documentation", - "url": "https://homarr.dev", - "behaviour": { - "onClickUrl": "https://homarr.dev", - "externalUrl": "https://homarr.dev", - "isOpeningNewTab": true - }, - "network": { - "enabledStatusChecker": false, - "okStatus": [ - 200 - ] - }, - "appearance": { - "iconUrl": "/imgs/logo/logo.png" - }, - "integration": { - "type": null, - "properties": [] - }, - "area": { - "type": "category", - "properties": { - "id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f" - } - }, - "shape": { - "md": { - "location": { - "x": 0, - "y": 10 - }, - "size": { - "width": 2, - "height": 1 - } - }, - "sm": { - "location": { - "x": 0, - "y": 10 - }, - "size": { - "width": 2, - "height": 1 - } - }, - "lg": { - "location": { - "x": 0, - "y": 10 - }, - "size": { - "width": 2, - "height": 1 - } } } }, @@ -376,64 +434,6 @@ "type": null, "properties": [] } - }, - { - "id": "5df743d9-5cb1-457c-85d2-64ff86855652", - "name": "Your app", - "url": "https://homarr.dev", - "appearance": { - "iconUrl": "/imgs/logo/logo.png" - }, - "network": { - "enabledStatusChecker": false, - "okStatus": [] - }, - "behaviour": { - "isOpeningNewTab": true, - "externalUrl": "https://homarr.dev" - }, - "area": { - "type": "category", - "properties": { - "id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f" - } - }, - "shape": { - "md": { - "location": { - "x": 3, - "y": 0 - }, - "size": { - "width": 1, - "height": 1 - } - }, - "sm": { - "location": { - "x": 2, - "y": 3 - }, - "size": { - "width": 1, - "height": 1 - } - }, - "lg": { - "location": { - "x": 6, - "y": 0 - }, - "size": { - "width": 1, - "height": 1 - } - } - }, - "integration": { - "type": null, - "properties": [] - } } ], "widgets": [ @@ -496,11 +496,11 @@ "shape": { "md": { "location": { - "x": 0, + "x": 4, "y": 0 }, "size": { - "width": 3, + "width": 2, "height": 1 } }, @@ -516,11 +516,11 @@ }, "lg": { "location": { - "x": 4, + "x": 0, "y": 1 }, "size": { - "width": 3, + "width": 2, "height": 1 } } @@ -540,28 +540,28 @@ "shape": { "sm": { "location": { - "x": 0, + "x": 1, "y": 1 }, - "size": { - "width": 3, - "height": 1 - } - }, - "md": { - "location": { - "x": 4, - "y": 0 - }, "size": { "width": 2, "height": 2 } }, + "md": { + "location": { + "x": 4, + "y": 2 + }, + "size": { + "width": 2, + "height": 1 + } + }, "lg": { "location": { - "x": 5, - "y": 2 + "x": 2, + "y": 0 }, "size": { "width": 2, diff --git a/src/components/Dashboard/Mobile/Ribbon/MobileRibbonSidebarDrawer.tsx b/src/components/Dashboard/Mobile/Ribbon/MobileRibbonSidebarDrawer.tsx index b09749ea2..22fb2df77 100644 --- a/src/components/Dashboard/Mobile/Ribbon/MobileRibbonSidebarDrawer.tsx +++ b/src/components/Dashboard/Mobile/Ribbon/MobileRibbonSidebarDrawer.tsx @@ -20,6 +20,6 @@ export const MobileRibbonSidebarDrawer = ({ }} {...props} > - + ); diff --git a/src/components/Dashboard/Views/DashboardView.tsx b/src/components/Dashboard/Views/DashboardView.tsx index ae2388017..cce453ad1 100644 --- a/src/components/Dashboard/Views/DashboardView.tsx +++ b/src/components/Dashboard/Views/DashboardView.tsx @@ -21,6 +21,7 @@ export const DashboardView = () => { const mainAreaWidth = useGridstackStore(x => x.mainAreaWidth); useEffect(() => { + if (width === 0) return; setMainAreaWidth(width); }, [width]); @@ -29,8 +30,8 @@ export const DashboardView = () => { {notReady ?
: <> - {layoutSettings?.enabledLeftSidebar && !doNotShowSidebar && mainAreaWidth ? ( - + {layoutSettings?.enabledLeftSidebar && !doNotShowSidebar ? ( + ) : null} {!mainAreaWidth ? null : wrappers.map((item) => @@ -41,8 +42,8 @@ export const DashboardView = () => { ) )} - {layoutSettings?.enabledRightSidebar && !doNotShowSidebar && mainAreaWidth ? ( - + {layoutSettings?.enabledRightSidebar && !doNotShowSidebar ? ( + ) : null} } diff --git a/src/components/Dashboard/Wrappers/Sidebar/Sidebar.tsx b/src/components/Dashboard/Wrappers/Sidebar/Sidebar.tsx index cefbf3538..08a3af69a 100644 --- a/src/components/Dashboard/Wrappers/Sidebar/Sidebar.tsx +++ b/src/components/Dashboard/Wrappers/Sidebar/Sidebar.tsx @@ -3,16 +3,12 @@ import { RefObject } from 'react'; import { useGridstack } from '../gridstack/use-gridstack'; import { WrapperContent } from '../WrapperContent'; -interface DashboardSidebarProps { +interface DashboardSidebarProps extends DashboardSidebarInnerProps { location: 'right' | 'left'; + isGridstackReady: boolean; } -export const DashboardSidebar = ({ location }: DashboardSidebarProps) => { - const { refs, apps, widgets } = useGridstack('sidebar', location); - - const minRow = useMinRowForFullHeight(refs.wrapper); - - return ( +export const DashboardSidebar = ({ location, isGridstackReady }: DashboardSidebarProps) => ( { borderStyle: 'dashed', }} > -
- -
+ {isGridstackReady && }
); + + interface DashboardSidebarInnerProps { + location: 'right' | 'left'; + } + +// Is Required because of the gridstack main area width. +const SidebarInner = ({ location }: DashboardSidebarInnerProps) => { + const { refs, apps, widgets } = useGridstack('sidebar', location); + + const minRow = useMinRowForFullHeight(refs.wrapper); + + return ( +
+ +
); }; const useMinRowForFullHeight = (wrapperRef: RefObject) => - wrapperRef.current ? Math.floor(wrapperRef.current!.offsetHeight / 64) : 2; + wrapperRef.current ? Math.floor(wrapperRef.current!.offsetHeight / 128) : 2; diff --git a/src/components/Dashboard/Wrappers/gridstack/init-gridstack.ts b/src/components/Dashboard/Wrappers/gridstack/init-gridstack.ts index c3a739468..f95d01fe1 100644 --- a/src/components/Dashboard/Wrappers/gridstack/init-gridstack.ts +++ b/src/components/Dashboard/Wrappers/gridstack/init-gridstack.ts @@ -1,6 +1,7 @@ import { GridStack, GridStackNode } from 'fily-publish-gridstack'; import { MutableRefObject, RefObject } from 'react'; import { AppType } from '../../../../types/app'; +import { ShapeType } from '../../../../types/shape'; import { IWidget } from '../../../../widgets/widgets'; export const initializeGridstack = ( @@ -13,6 +14,7 @@ export const initializeGridstack = ( widgets: IWidget[], isEditMode: boolean, wrapperColumnCount: 3 | 6 | 12, + shapeSize: 'sm' | 'md' | 'lg', events: { onChange: (changedNode: GridStackNode) => void; onAdd: (addedNode: GridStackNode) => void; @@ -21,14 +23,14 @@ export const initializeGridstack = ( if (!wrapperRef.current) return; // calculates the currently available count of columns const columnCount = areaType === 'sidebar' ? 2 : wrapperColumnCount; - const minRow = areaType !== 'sidebar' ? 1 : Math.floor(wrapperRef.current.offsetHeight / 64); + const minRow = areaType !== 'sidebar' ? 1 : Math.floor(wrapperRef.current.offsetHeight / 128); // initialize gridstack const newGrid = gridRef; newGrid.current = GridStack.init( { column: columnCount, margin: 10, - cellHeight: 64, + cellHeight: 128, float: true, alwaysShowResizeHandle: 'mobile', acceptWidgets: true, @@ -63,16 +65,26 @@ export const initializeGridstack = ( grid.batchUpdate(); grid.removeAll(false); items.forEach( - ({ id }) => { + ({ id, shape }) => { const item = itemRefs.current[id]?.current; + setAttributesFromShape(item, shape[shapeSize]); item && grid.makeWidget(item as HTMLDivElement); } ); widgets.forEach( - ({ id }) => { + ({ id, shape }) => { const item = itemRefs.current[id]?.current; + setAttributesFromShape(item, shape[shapeSize]); item && grid.makeWidget(item as HTMLDivElement); } ); grid.batchUpdate(false); }; + +function setAttributesFromShape(ref: HTMLDivElement | null, sizedShape: ShapeType['lg']) { + if (!sizedShape || !ref) return; + ref.setAttribute('gs-x', sizedShape.location.x.toString()); + ref.setAttribute('gs-y', sizedShape.location.y.toString()); + ref.setAttribute('gs-w', sizedShape.size.width.toString()); + ref.setAttribute('gs-h', sizedShape.size.height.toString()); +} diff --git a/src/components/Dashboard/Wrappers/gridstack/use-gridstack.ts b/src/components/Dashboard/Wrappers/gridstack/use-gridstack.ts index 5f5b74a5f..5f0bcf4c4 100644 --- a/src/components/Dashboard/Wrappers/gridstack/use-gridstack.ts +++ b/src/components/Dashboard/Wrappers/gridstack/use-gridstack.ts @@ -243,6 +243,7 @@ export const useGridstack = ( widgets ?? [], isEditMode, wrapperColumnCount, + shapeSize, { onChange, onAdd, diff --git a/src/hooks/use-resize.ts b/src/hooks/use-resize.ts index 6f479348d..e9c47cf15 100644 --- a/src/hooks/use-resize.ts +++ b/src/hooks/use-resize.ts @@ -1,17 +1,22 @@ -import { useCallback, useEffect, useState, MutableRefObject } from 'react'; +import { MutableRefObject, useCallback, useEffect, useState } from 'react'; export const useResize = (myRef: MutableRefObject, dependencies: any[]) => { const [width, setWidth] = useState(0); const [height, setHeight] = useState(0); const handleResize = useCallback(() => { - setWidth(myRef.current?.offsetWidth ?? 0); - setHeight(myRef.current?.offsetHeight ?? 0); + if (!myRef.current) return; + setWidth(myRef.current.offsetWidth); + setHeight(myRef.current.offsetHeight); }, [myRef]); useEffect(() => { - window.addEventListener('load', handleResize); - window.addEventListener('resize', handleResize); + window.addEventListener('load', () => + handleResize() + ); + window.addEventListener('resize', () => + handleResize() + ); return () => { window.removeEventListener('load', handleResize); diff --git a/src/styles/global.scss b/src/styles/global.scss index 0f84d11a9..026e01066 100644 --- a/src/styles/global.scss +++ b/src/styles/global.scss @@ -17,6 +17,7 @@ } } +// Styling for grid-stack main area @for $i from 1 to 13 { .grid-stack>.grid-stack-item[gs-w="#{$i}"] { width: calc(100% / #{var(--gridstack-column-count)} * #{$i}) } .grid-stack>.grid-stack-item[gs-min-w="#{$i}"] { min-width: calc(100% / #{var(--gridstack-column-count)} * #{$i}) } @@ -38,6 +39,37 @@ .grid-stack>.grid-stack-item[gs-y="#{$i}"] { top: calc(#{$i} * #{var(--gridstack-widget-width)}) } } +.grid-stack>.grid-stack-item { + min-width: calc(percentage(1) * #{var(--gridstack-widget-width)}); +} + +// Styling for sidebar grid-stack elements +@for $i from 1 to 3 { + .grid-stack.grid-stack-sidebar>.grid-stack-item[gs-w="#{$i}"] { width: 128px * $i } + .grid-stack.grid-stack-sidebar>.grid-stack-item[gs-min-w="#{$i}"] { min-width: 128px * $i } + .grid-stack.grid-stack-sidebar>.grid-stack-item[gs-max-w="#{$i}"] { max-width: 128px * $i } +} + +@for $i from 1 to 96 { + .grid-stack.grid-stack-sidebar>.grid-stack-item[gs-h="#{$i}"] { height: 128px * $i } + .grid-stack.grid-stack-sidebar>.grid-stack-item[gs-min-h="#{$i}"] { min-height: 128px * $i } + .grid-stack.grid-stack-sidebar>.grid-stack-item[gs-max-h="#{$i}"] { max-height: 128px * $i } +} + +@for $i from 1 to 13 { + .grid-stack.grid-stack-sidebar>.grid-stack-item[gs-x="#{$i}"] { left: 128px * $i } +} + + +@for $i from 1 to 96 { + .grid-stack.grid-stack-sidebar>.grid-stack-item[gs-y="#{$i}"] { top: 128px * $i } +} + +.grid-stack.grid-stack-sidebar>.grid-stack-item { + min-width: 128px; +} + +// General gridstack styling .grid-stack>.grid-stack-item>.grid-stack-item-content, .grid-stack>.grid-stack-item>.placeholder-content { inset: 10px; @@ -48,10 +80,6 @@ right: 10px; } -.grid-stack>.grid-stack-item { - min-width: calc(percentage(1) * #{var(--gridstack-widget-width)}); -} - .grid-stack > .grid-stack-item > .grid-stack-item-content { overflow-y: hidden; }