🐛 Sidebars not working

This commit is contained in:
Meierschlumpf
2023-01-06 23:50:08 +01:00
parent 9608452bed
commit d26128af0e
8 changed files with 366 additions and 310 deletions

View File

@@ -18,8 +18,69 @@
], ],
"apps": [ "apps": [
{ {
"id": "76217a87-7151-42d0-b0cf-1b72aef63f83", "id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33a",
"name": "Small app", "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", "url": "https://homarr.dev",
"appearance": { "appearance": {
"iconUrl": "/imgs/logo/logo.png" "iconUrl": "/imgs/logo/logo.png"
@@ -41,7 +102,7 @@
"shape": { "shape": {
"md": { "md": {
"location": { "location": {
"x": 1, "x": 5,
"y": 1 "y": 1
}, },
"size": { "size": {
@@ -51,8 +112,8 @@
}, },
"sm": { "sm": {
"location": { "location": {
"x": 0, "x": 2,
"y": 3 "y": 0
}, },
"size": { "size": {
"width": 1, "width": 1,
@@ -61,7 +122,187 @@
}, },
"lg": { "lg": {
"location": { "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 "y": 0
}, },
"size": { "size": {
@@ -105,6 +346,16 @@
}, },
"shape": { "shape": {
"md": { "md": {
"location": {
"x": 0,
"y": 0
},
"size": {
"width": 1,
"height": 4
}
},
"sm": {
"location": { "location": {
"x": 0, "x": 0,
"y": 1 "y": 1
@@ -114,208 +365,15 @@
"height": 1 "height": 1
} }
}, },
"sm": {
"location": {
"x": 1,
"y": 2
},
"size": {
"width": 1,
"height": 1
}
},
"lg": { "lg": {
"location": { "location": {
"x": 0, "x": 0,
"y": 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": { "size": {
"width": 1, "width": 1,
"height": 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, "type": null,
"properties": [] "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": [ "widgets": [
@@ -496,11 +496,11 @@
"shape": { "shape": {
"md": { "md": {
"location": { "location": {
"x": 0, "x": 4,
"y": 0 "y": 0
}, },
"size": { "size": {
"width": 3, "width": 2,
"height": 1 "height": 1
} }
}, },
@@ -516,11 +516,11 @@
}, },
"lg": { "lg": {
"location": { "location": {
"x": 4, "x": 0,
"y": 1 "y": 1
}, },
"size": { "size": {
"width": 3, "width": 2,
"height": 1 "height": 1
} }
} }
@@ -540,28 +540,28 @@
"shape": { "shape": {
"sm": { "sm": {
"location": { "location": {
"x": 0, "x": 1,
"y": 1 "y": 1
}, },
"size": {
"width": 3,
"height": 1
}
},
"md": {
"location": {
"x": 4,
"y": 0
},
"size": { "size": {
"width": 2, "width": 2,
"height": 2 "height": 2
} }
}, },
"md": {
"location": {
"x": 4,
"y": 2
},
"size": {
"width": 2,
"height": 1
}
},
"lg": { "lg": {
"location": { "location": {
"x": 5, "x": 2,
"y": 2 "y": 0
}, },
"size": { "size": {
"width": 2, "width": 2,

View File

@@ -20,6 +20,6 @@ export const MobileRibbonSidebarDrawer = ({
}} }}
{...props} {...props}
> >
<DashboardSidebar location={location} /> <DashboardSidebar location={location} isGridstackReady />
</Drawer> </Drawer>
); );

View File

@@ -21,6 +21,7 @@ export const DashboardView = () => {
const mainAreaWidth = useGridstackStore(x => x.mainAreaWidth); const mainAreaWidth = useGridstackStore(x => x.mainAreaWidth);
useEffect(() => { useEffect(() => {
if (width === 0) return;
setMainAreaWidth(width); setMainAreaWidth(width);
}, [width]); }, [width]);
@@ -29,8 +30,8 @@ export const DashboardView = () => {
{notReady ? <Center w="100%"> {notReady ? <Center w="100%">
<Loader /> <Loader />
</Center> : <> </Center> : <>
{layoutSettings?.enabledLeftSidebar && !doNotShowSidebar && mainAreaWidth ? ( {layoutSettings?.enabledLeftSidebar && !doNotShowSidebar ? (
<DashboardSidebar location="left" /> <DashboardSidebar location="left" isGridstackReady={!!mainAreaWidth} />
) : null} ) : null}
<Stack ref={mainAreaRef} mx={-10} style={{ flexGrow: 1 }}> <Stack ref={mainAreaRef} mx={-10} style={{ flexGrow: 1 }}>
{!mainAreaWidth ? null : wrappers.map((item) => {!mainAreaWidth ? null : wrappers.map((item) =>
@@ -41,8 +42,8 @@ export const DashboardView = () => {
) )
)} )}
</Stack> </Stack>
{layoutSettings?.enabledRightSidebar && !doNotShowSidebar && mainAreaWidth ? ( {layoutSettings?.enabledRightSidebar && !doNotShowSidebar ? (
<DashboardSidebar location="right" /> <DashboardSidebar location="right" isGridstackReady={!!mainAreaWidth} />
) : null} ) : null}
</> </>
} }

View File

@@ -3,16 +3,12 @@ import { RefObject } from 'react';
import { useGridstack } from '../gridstack/use-gridstack'; import { useGridstack } from '../gridstack/use-gridstack';
import { WrapperContent } from '../WrapperContent'; import { WrapperContent } from '../WrapperContent';
interface DashboardSidebarProps { interface DashboardSidebarProps extends DashboardSidebarInnerProps {
location: 'right' | 'left'; location: 'right' | 'left';
isGridstackReady: boolean;
} }
export const DashboardSidebar = ({ location }: DashboardSidebarProps) => { export const DashboardSidebar = ({ location, isGridstackReady }: DashboardSidebarProps) => (
const { refs, apps, widgets } = useGridstack('sidebar', location);
const minRow = useMinRowForFullHeight(refs.wrapper);
return (
<Card <Card
withBorder withBorder
w={300} w={300}
@@ -21,6 +17,21 @@ export const DashboardSidebar = ({ location }: DashboardSidebarProps) => {
borderStyle: 'dashed', borderStyle: 'dashed',
}} }}
> >
{isGridstackReady && <SidebarInner location={location} />}
</Card>
);
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 (
<div <div
className="grid-stack grid-stack-sidebar" className="grid-stack grid-stack-sidebar"
style={{ transitionDuration: '0s', height: '100%' }} style={{ transitionDuration: '0s', height: '100%' }}
@@ -30,10 +41,8 @@ export const DashboardSidebar = ({ location }: DashboardSidebarProps) => {
ref={refs.wrapper} ref={refs.wrapper}
> >
<WrapperContent apps={apps} refs={refs} widgets={widgets} /> <WrapperContent apps={apps} refs={refs} widgets={widgets} />
</div> </div>);
</Card>
);
}; };
const useMinRowForFullHeight = (wrapperRef: RefObject<HTMLDivElement>) => const useMinRowForFullHeight = (wrapperRef: RefObject<HTMLDivElement>) =>
wrapperRef.current ? Math.floor(wrapperRef.current!.offsetHeight / 64) : 2; wrapperRef.current ? Math.floor(wrapperRef.current!.offsetHeight / 128) : 2;

View File

@@ -1,6 +1,7 @@
import { GridStack, GridStackNode } from 'fily-publish-gridstack'; import { GridStack, GridStackNode } from 'fily-publish-gridstack';
import { MutableRefObject, RefObject } from 'react'; import { MutableRefObject, RefObject } from 'react';
import { AppType } from '../../../../types/app'; import { AppType } from '../../../../types/app';
import { ShapeType } from '../../../../types/shape';
import { IWidget } from '../../../../widgets/widgets'; import { IWidget } from '../../../../widgets/widgets';
export const initializeGridstack = ( export const initializeGridstack = (
@@ -13,6 +14,7 @@ export const initializeGridstack = (
widgets: IWidget<string, any>[], widgets: IWidget<string, any>[],
isEditMode: boolean, isEditMode: boolean,
wrapperColumnCount: 3 | 6 | 12, wrapperColumnCount: 3 | 6 | 12,
shapeSize: 'sm' | 'md' | 'lg',
events: { events: {
onChange: (changedNode: GridStackNode) => void; onChange: (changedNode: GridStackNode) => void;
onAdd: (addedNode: GridStackNode) => void; onAdd: (addedNode: GridStackNode) => void;
@@ -21,14 +23,14 @@ export const initializeGridstack = (
if (!wrapperRef.current) return; if (!wrapperRef.current) return;
// calculates the currently available count of columns // calculates the currently available count of columns
const columnCount = areaType === 'sidebar' ? 2 : wrapperColumnCount; 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 // initialize gridstack
const newGrid = gridRef; const newGrid = gridRef;
newGrid.current = GridStack.init( newGrid.current = GridStack.init(
{ {
column: columnCount, column: columnCount,
margin: 10, margin: 10,
cellHeight: 64, cellHeight: 128,
float: true, float: true,
alwaysShowResizeHandle: 'mobile', alwaysShowResizeHandle: 'mobile',
acceptWidgets: true, acceptWidgets: true,
@@ -63,16 +65,26 @@ export const initializeGridstack = (
grid.batchUpdate(); grid.batchUpdate();
grid.removeAll(false); grid.removeAll(false);
items.forEach( items.forEach(
({ id }) => { ({ id, shape }) => {
const item = itemRefs.current[id]?.current; const item = itemRefs.current[id]?.current;
setAttributesFromShape(item, shape[shapeSize]);
item && grid.makeWidget(item as HTMLDivElement); item && grid.makeWidget(item as HTMLDivElement);
} }
); );
widgets.forEach( widgets.forEach(
({ id }) => { ({ id, shape }) => {
const item = itemRefs.current[id]?.current; const item = itemRefs.current[id]?.current;
setAttributesFromShape(item, shape[shapeSize]);
item && grid.makeWidget(item as HTMLDivElement); item && grid.makeWidget(item as HTMLDivElement);
} }
); );
grid.batchUpdate(false); 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());
}

View File

@@ -243,6 +243,7 @@ export const useGridstack = (
widgets ?? [], widgets ?? [],
isEditMode, isEditMode,
wrapperColumnCount, wrapperColumnCount,
shapeSize,
{ {
onChange, onChange,
onAdd, onAdd,

View File

@@ -1,17 +1,22 @@
import { useCallback, useEffect, useState, MutableRefObject } from 'react'; import { MutableRefObject, useCallback, useEffect, useState } from 'react';
export const useResize = (myRef: MutableRefObject<HTMLDivElement | null>, dependencies: any[]) => { export const useResize = (myRef: MutableRefObject<HTMLDivElement | null>, dependencies: any[]) => {
const [width, setWidth] = useState(0); const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0); const [height, setHeight] = useState(0);
const handleResize = useCallback(() => { const handleResize = useCallback(() => {
setWidth(myRef.current?.offsetWidth ?? 0); if (!myRef.current) return;
setHeight(myRef.current?.offsetHeight ?? 0); setWidth(myRef.current.offsetWidth);
setHeight(myRef.current.offsetHeight);
}, [myRef]); }, [myRef]);
useEffect(() => { useEffect(() => {
window.addEventListener('load', handleResize); window.addEventListener('load', () =>
window.addEventListener('resize', handleResize); handleResize()
);
window.addEventListener('resize', () =>
handleResize()
);
return () => { return () => {
window.removeEventListener('load', handleResize); window.removeEventListener('load', handleResize);

View File

@@ -17,6 +17,7 @@
} }
} }
// Styling for grid-stack main area
@for $i from 1 to 13 { @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-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}) } .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[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>.grid-stack-item-content,
.grid-stack>.grid-stack-item>.placeholder-content { .grid-stack>.grid-stack-item>.placeholder-content {
inset: 10px; inset: 10px;
@@ -48,10 +80,6 @@
right: 10px; 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 { .grid-stack > .grid-stack-item > .grid-stack-item-content {
overflow-y: hidden; overflow-y: hidden;
} }