mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-10 15:35:55 +01:00
🐛 Improve resposivnes
This commit is contained in:
@@ -17,81 +17,6 @@
|
||||
}
|
||||
],
|
||||
"apps": [
|
||||
{
|
||||
"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": "wrapper",
|
||||
"properties": {
|
||||
"id": "default"
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"location": {
|
||||
"x": 0,
|
||||
"y": 11
|
||||
},
|
||||
"size": {
|
||||
"width": 4,
|
||||
"height": 3
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "e41a11f5-9c6e-41bc-ac0e-4c4c47582faa",
|
||||
"name": "Your app",
|
||||
"url": "https://homarr.dev",
|
||||
"appearance": {
|
||||
"iconUrl": "/imgs/logo/logo.png"
|
||||
},
|
||||
"network": {
|
||||
"enabledStatusChecker": false,
|
||||
"okStatus": []
|
||||
},
|
||||
"behaviour": {
|
||||
"isOpeningNewTab": true,
|
||||
"externalUrl": ""
|
||||
},
|
||||
"area": {
|
||||
"type": "wrapper",
|
||||
"properties": {
|
||||
"id": "default"
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"location": {
|
||||
"x": 8,
|
||||
"y": 10
|
||||
},
|
||||
"size": {
|
||||
"width": 4,
|
||||
"height": 2
|
||||
}
|
||||
},
|
||||
"integration": {
|
||||
"type": null,
|
||||
"properties": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "5df743d9-5cb1-457c-85d2-64ff86855652",
|
||||
"name": "Your app",
|
||||
@@ -128,6 +53,42 @@
|
||||
"properties": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": "category",
|
||||
"properties": {
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f"
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"location": {
|
||||
"x": 4,
|
||||
"y": 0
|
||||
},
|
||||
"size": {
|
||||
"width": 1,
|
||||
"height": 1
|
||||
}
|
||||
},
|
||||
"integration": {
|
||||
"type": null,
|
||||
"properties": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a330",
|
||||
"name": "Contribute",
|
||||
@@ -158,7 +119,7 @@
|
||||
},
|
||||
"shape": {
|
||||
"location": {
|
||||
"x": 4,
|
||||
"x": 7,
|
||||
"y": 0
|
||||
},
|
||||
"size": {
|
||||
@@ -167,42 +128,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": "category",
|
||||
"properties": {
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f"
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"location": {
|
||||
"x": 5,
|
||||
"y": 0
|
||||
},
|
||||
"size": {
|
||||
"width": 1,
|
||||
"height": 1
|
||||
}
|
||||
},
|
||||
"integration": {
|
||||
"type": null,
|
||||
"properties": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a337",
|
||||
"name": "Discord",
|
||||
@@ -242,6 +167,45 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": "wrapper",
|
||||
"properties": {
|
||||
"id": "default"
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"location": {
|
||||
"x": 0,
|
||||
"y": 11
|
||||
},
|
||||
"size": {
|
||||
"width": 4,
|
||||
"height": 3
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a990",
|
||||
"name": "Donate",
|
||||
@@ -272,7 +236,7 @@
|
||||
},
|
||||
"shape": {
|
||||
"location": {
|
||||
"x": 7,
|
||||
"x": 5,
|
||||
"y": 0
|
||||
},
|
||||
"size": {
|
||||
@@ -280,54 +244,45 @@
|
||||
"height": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "e41a11f5-9c6e-41bc-ac0e-4c4c47582faa",
|
||||
"name": "Your app",
|
||||
"url": "https://homarr.dev",
|
||||
"appearance": {
|
||||
"iconUrl": "/imgs/logo/logo.png"
|
||||
},
|
||||
"network": {
|
||||
"enabledStatusChecker": false,
|
||||
"okStatus": []
|
||||
},
|
||||
"behaviour": {
|
||||
"isOpeningNewTab": true,
|
||||
"externalUrl": ""
|
||||
},
|
||||
"area": {
|
||||
"type": "wrapper",
|
||||
"properties": {
|
||||
"id": "default"
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"location": {
|
||||
"x": 8,
|
||||
"y": 10
|
||||
},
|
||||
"size": {
|
||||
"width": 4,
|
||||
"height": 2
|
||||
}
|
||||
},
|
||||
"integration": {
|
||||
"type": null,
|
||||
"properties": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"widgets": [
|
||||
{
|
||||
"id": "weather",
|
||||
"properties": {
|
||||
"displayInFahrenheit": false,
|
||||
"location": "Paris"
|
||||
},
|
||||
"area": {
|
||||
"type": "category",
|
||||
"properties": {
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f"
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"location": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"size": {
|
||||
"width": 2,
|
||||
"height": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "date",
|
||||
"properties": {
|
||||
"display24HourFormat": true
|
||||
},
|
||||
"area": {
|
||||
"type": "category",
|
||||
"properties": {
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f"
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"location": {
|
||||
"x": 2,
|
||||
"y": 0
|
||||
},
|
||||
"size": {
|
||||
"width": 2,
|
||||
"height": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "calendar",
|
||||
"properties": {
|
||||
@@ -349,6 +304,51 @@
|
||||
"height": 5
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "weather",
|
||||
"properties": {
|
||||
"displayInFahrenheit": false,
|
||||
"location": "Paris"
|
||||
},
|
||||
"area": {
|
||||
"type": "category",
|
||||
"properties": {
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f"
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"location": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"size": {
|
||||
"width": 4,
|
||||
"height": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "date",
|
||||
"properties": {
|
||||
"display24HourFormat": true
|
||||
},
|
||||
"area": {
|
||||
"type": "category",
|
||||
"properties": {
|
||||
"id": "47af36c0-47c1-4e5b-bfc7-ad645ee6a33f"
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"location": {
|
||||
"x": 8,
|
||||
"y": 0
|
||||
},
|
||||
"size": {
|
||||
"width": 4,
|
||||
"height": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
|
||||
@@ -12,7 +12,7 @@ export const initializeGridstack = (
|
||||
items: AppType[],
|
||||
widgets: IWidget<string, any>[],
|
||||
isEditMode: boolean,
|
||||
isLargerThanSm: boolean,
|
||||
wrapperColumnCount: 3 | 6 | 12,
|
||||
events: {
|
||||
onChange: (changedNode: GridStackNode) => void;
|
||||
onAdd: (addedNode: GridStackNode) => void;
|
||||
@@ -20,7 +20,7 @@ export const initializeGridstack = (
|
||||
) => {
|
||||
if (!wrapperRef.current) return;
|
||||
// calculates the currently available count of columns
|
||||
const columnCount = areaType === 'sidebar' ? 4 : isLargerThanSm || typeof isLargerThanSm === 'undefined' ? 12 : 6;
|
||||
const columnCount = areaType === 'sidebar' ? 4 : wrapperColumnCount;
|
||||
const minRow = areaType !== 'sidebar' ? 1 : Math.floor(wrapperRef.current.offsetHeight / 64);
|
||||
// initialize gridstack
|
||||
const newGrid = gridRef;
|
||||
|
||||
@@ -28,11 +28,18 @@ interface UseGristackReturnType {
|
||||
};
|
||||
}
|
||||
|
||||
const useWrapperColumnCount = () => {
|
||||
const isLargerThanSm = useScreenLargerThan('sm');
|
||||
const isLargerThanXl = useScreenLargerThan('xl');
|
||||
|
||||
return typeof isLargerThanXl === 'undefined' || isLargerThanXl ? 12 : isLargerThanSm ? 6 : 3;
|
||||
};
|
||||
|
||||
export const useGridstack = (
|
||||
areaType: 'wrapper' | 'category' | 'sidebar',
|
||||
areaId: string
|
||||
): UseGristackReturnType => {
|
||||
const isLargerThanSm = useScreenLargerThan('sm');
|
||||
const wrapperColumnCount = useWrapperColumnCount();
|
||||
const isEditMode = useEditModeStore((x) => x.enabled);
|
||||
const { config, configVersion, name: configName } = useConfigContext();
|
||||
const updateConfig = useConfigStore((x) => x.updateConfig);
|
||||
@@ -82,59 +89,104 @@ export const useGridstack = (
|
||||
useEffect(() => {
|
||||
if (areaType === 'sidebar') return;
|
||||
gridRef.current?.column(
|
||||
isLargerThanSm || typeof isLargerThanSm === 'undefined' ? 12 : 6,
|
||||
wrapperColumnCount,
|
||||
(column, prevColumn, newNodes, nodes) => {
|
||||
let nextRow = 0;
|
||||
let available = 6;
|
||||
let available = column;
|
||||
|
||||
if (column === prevColumn) {
|
||||
newNodes.concat(nodes);
|
||||
return;
|
||||
}
|
||||
|
||||
nodes.reverse().forEach((node) => {
|
||||
const getGridstackAttribute = (node: GridStackNode, path: 'x' | 'y' | 'w' | 'h'): number => parseInt(node.el!.getAttribute(`data-gridstack-${path}`)!, 10);
|
||||
|
||||
const getGridstackAttributes = (node: GridStackNode) => ({
|
||||
width: getGridstackAttribute(node, 'w'),
|
||||
height: getGridstackAttribute(node, 'h'),
|
||||
x: getGridstackAttribute(node, 'x'),
|
||||
y: getGridstackAttribute(node, 'y'),
|
||||
});
|
||||
|
||||
const sortNodes = (a: GridStackNode, b: GridStackNode) => {
|
||||
const aAttributes = getGridstackAttributes(a);
|
||||
const bAttributes = getGridstackAttributes(b);
|
||||
|
||||
const differenceY = aAttributes.y - bAttributes.y;
|
||||
|
||||
return differenceY !== 0 ? differenceY : aAttributes.x - bAttributes.x;
|
||||
};
|
||||
|
||||
const sorted = nodes.sort(sortNodes);
|
||||
|
||||
console.log(sorted);
|
||||
|
||||
sorted.forEach((node) => {
|
||||
const newnode = node;
|
||||
const width = parseInt(newnode.el!.getAttribute('data-gridstack-w')!, 10);
|
||||
const height = parseInt(newnode.el!.getAttribute('data-gridstack-h')!, 10);
|
||||
const x = parseInt(newnode.el!.getAttribute('data-gridstack-x')!, 10);
|
||||
const y = parseInt(newnode.el!.getAttribute('data-gridstack-y')!, 10);
|
||||
const moveYDown = 1;
|
||||
|
||||
if (column === 6) {
|
||||
if (column === 3) {
|
||||
newnode.x = available >= width ? 3 - available : 0;
|
||||
newnode.y = available === 3 || available >= width ? nextRow : nextRow += moveYDown;
|
||||
|
||||
if (width > 3) {
|
||||
newnode.w = 3;
|
||||
nextRow += moveYDown;
|
||||
available = 3;
|
||||
} else if (available >= width) {
|
||||
available -= width;
|
||||
if (available === 0) {
|
||||
nextRow += moveYDown;
|
||||
available = 3;
|
||||
}
|
||||
} else if (available < width) {
|
||||
newnode.y = newnode.y! + moveYDown;
|
||||
available = 3 - width;
|
||||
nextRow += moveYDown;
|
||||
}
|
||||
} else if (column === 6) {
|
||||
newnode.x = available >= width ? 6 - available : 0;
|
||||
newnode.y = nextRow;
|
||||
|
||||
if (width > 6) {
|
||||
newnode.w = 6;
|
||||
nextRow += 2;
|
||||
nextRow += moveYDown;
|
||||
available = 6;
|
||||
} else if (available >= width) {
|
||||
available -= width;
|
||||
if (available === 0) {
|
||||
nextRow += 2;
|
||||
nextRow += moveYDown;
|
||||
available = 6;
|
||||
}
|
||||
} else if (available < width) {
|
||||
newnode.y = newnode.y! + 2;
|
||||
newnode.y = newnode.y! + moveYDown;
|
||||
available = 6 - width;
|
||||
nextRow += 2;
|
||||
nextRow += moveYDown;
|
||||
}
|
||||
} else {
|
||||
newnode.x = y % 2 === 1 ? x + 6 : x;
|
||||
newnode.y = Math.floor(y / 2);
|
||||
}
|
||||
|
||||
console.log(newnode);
|
||||
|
||||
newNodes.push(newnode);
|
||||
});
|
||||
}
|
||||
);
|
||||
}, [isLargerThanSm]);
|
||||
}, [wrapperColumnCount]);
|
||||
|
||||
useEffect(() => {
|
||||
if (width === 0) return;
|
||||
const widgetWidth = width / (isLargerThanSm ? 12 : 6);
|
||||
const widgetWidth = width / wrapperColumnCount;
|
||||
// widget width is used to define sizes of gridstack items within global.scss
|
||||
root.style.setProperty('--gridstack-widget-width', widgetWidth.toString());
|
||||
gridRef.current?.cellHeight(widgetWidth);
|
||||
}, [width, isLargerThanSm]);
|
||||
}, [width, wrapperColumnCount]);
|
||||
|
||||
const onChange = isEditMode
|
||||
? (changedNode: GridStackNode) => {
|
||||
@@ -291,7 +343,7 @@ export const useGridstack = (
|
||||
items,
|
||||
widgets ?? [],
|
||||
isEditMode,
|
||||
isLargerThanSm,
|
||||
wrapperColumnCount,
|
||||
{
|
||||
onChange,
|
||||
onAdd,
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
transition: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
@media screen and (max-width: 1400px) {
|
||||
@for $i from 1 to 7 {
|
||||
.grid-stack>.grid-stack-item[gs-w="#{$i}"] { width: percentage(($i / 6)) !important }
|
||||
.grid-stack>.grid-stack-item[gs-min-w="#{$i}"] { min-width: percentage(($i / 6)) !important }
|
||||
@@ -73,4 +73,20 @@
|
||||
.grid-stack>.grid-stack-item {
|
||||
min-width: percentage(1/6) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
@for $i from 1 to 4 {
|
||||
.grid-stack>.grid-stack-item[gs-w="#{$i}"] { width: percentage(($i / 3)) !important }
|
||||
.grid-stack>.grid-stack-item[gs-min-w="#{$i}"] { min-width: percentage(($i / 3)) !important }
|
||||
.grid-stack>.grid-stack-item[gs-max-w="#{$i}"] { max-width: percentage(($i / 3)) !important }
|
||||
}
|
||||
|
||||
@for $i from 1 to 4 {
|
||||
.grid-stack>.grid-stack-item[gs-x="#{$i}"] { left: percentage(($i / 3)) }
|
||||
}
|
||||
|
||||
.grid-stack>.grid-stack-item {
|
||||
min-width: percentage(1/3) !important;
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ const definition = defineWidget({
|
||||
},
|
||||
gridstack: {
|
||||
minWidth: 2,
|
||||
minHeight: 2,
|
||||
minHeight: 1,
|
||||
maxWidth: 12,
|
||||
maxHeight: 12,
|
||||
},
|
||||
|
||||
@@ -20,7 +20,7 @@ const definition = defineWidget({
|
||||
},
|
||||
gridstack: {
|
||||
minWidth: 2,
|
||||
minHeight: 2,
|
||||
minHeight: 1,
|
||||
maxWidth: 12,
|
||||
maxHeight: 12,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user