From c2d34cd0eb39c913b9c5dfda7b4d9dec90d996d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Sun, 14 Apr 2019 16:07:42 +0100 Subject: [PATCH] feat(ui): dynamically calculate grid size This allows to have dynamic grid size, rather than static with values hardcoded in Constants file --- ui/src/Components/Grid/AlertGrid/Constants.js | 34 ------ ui/src/Components/Grid/AlertGrid/GridSize.js | 33 ++++++ ui/src/Components/Grid/AlertGrid/index.js | 18 ++- .../Components/Grid/AlertGrid/index.test.js | 110 ++++++++++-------- 4 files changed, 105 insertions(+), 90 deletions(-) delete mode 100644 ui/src/Components/Grid/AlertGrid/Constants.js create mode 100644 ui/src/Components/Grid/AlertGrid/GridSize.js diff --git a/ui/src/Components/Grid/AlertGrid/Constants.js b/ui/src/Components/Grid/AlertGrid/Constants.js deleted file mode 100644 index 21c227abc..000000000 --- a/ui/src/Components/Grid/AlertGrid/Constants.js +++ /dev/null @@ -1,34 +0,0 @@ -// grid sizes, defines how many columns are used depending on the screen width -// this is config as expected by https://github.com/callmecavs/bricks.js#sizes -const GridSizesConfig = [ - { columns: 1, gutter: 0 }, - { mq: "800px", columns: 2, gutter: 0 }, - { mq: "1400px", columns: 3, gutter: 0 }, - { mq: "2100px", columns: 4, gutter: 0 }, - { mq: "2800px", columns: 5, gutter: 0 }, - { mq: "3500px", columns: 6, gutter: 0 }, - { mq: "4200px", columns: 7, gutter: 0 }, - { mq: "4900px", columns: 7, gutter: 0 }, - { mq: "5600px", columns: 8, gutter: 0 } -]; - -const GetGridElementWidth = canvasWidth => - Math.floor( - canvasWidth < 800 - ? canvasWidth - : canvasWidth < 1400 - ? canvasWidth / 2 - : canvasWidth < 2100 - ? canvasWidth / 3 - : canvasWidth < 2800 - ? canvasWidth / 4 - : canvasWidth < 3500 - ? canvasWidth / 5 - : canvasWidth < 4200 - ? canvasWidth / 6 - : canvasWidth < 5600 - ? canvasWidth / 7 - : canvasWidth / 8 - ); - -export { GridSizesConfig, GetGridElementWidth }; diff --git a/ui/src/Components/Grid/AlertGrid/GridSize.js b/ui/src/Components/Grid/AlertGrid/GridSize.js new file mode 100644 index 000000000..97eae2934 --- /dev/null +++ b/ui/src/Components/Grid/AlertGrid/GridSize.js @@ -0,0 +1,33 @@ +const baseWidth = 400; + +const MinWidth = canvasWidth => + Math.floor( + baseWidth + (canvasWidth / Math.min(canvasWidth, baseWidth * 2)) * 10 + ); + +// grid sizes, defines how many columns are used depending on the screen width +// this is config as expected by https://github.com/callmecavs/bricks.js#sizes +const GridSizesConfig = canvasWidth => { + const generatedSizes = []; + for (let i = 2; i < 20; i++) { + generatedSizes.push({ + mq: `${i * MinWidth(i * baseWidth)}px`, + columns: i, + gutter: 0 + }); + } + //console.info(JSON.stringify(generatedSizes)); + return [...[{ columns: 1, gutter: 0 }], ...generatedSizes]; +}; + +const GetGridElementWidth = canvasWidth => { + const mw = MinWidth(canvasWidth); + return Math.floor( + Math.min( + mw + (canvasWidth % mw) / Math.floor(canvasWidth / mw), + canvasWidth + ) + ); +}; + +export { MinWidth, GridSizesConfig, GetGridElementWidth }; diff --git a/ui/src/Components/Grid/AlertGrid/index.js b/ui/src/Components/Grid/AlertGrid/index.js index ccfe9a800..032bc6502 100644 --- a/ui/src/Components/Grid/AlertGrid/index.js +++ b/ui/src/Components/Grid/AlertGrid/index.js @@ -1,7 +1,7 @@ import React, { Component } from "react"; import PropTypes from "prop-types"; -import { observable, action } from "mobx"; +import { observable, action, computed } from "mobx"; import { observer } from "mobx-react"; import FontFaceObserver from "fontfaceobserver"; @@ -21,7 +21,7 @@ import { AlertStore } from "Stores/AlertStore"; import { Settings } from "Stores/Settings"; import { SilenceFormStore } from "Stores/SilenceFormStore"; import { AlertGroup } from "./AlertGroup"; -import { GridSizesConfig, GetGridElementWidth } from "./Constants"; +import { GridSizesConfig, GetGridElementWidth } from "./GridSize"; import "./index.css"; @@ -42,12 +42,20 @@ const AlertGrid = observer( this.viewport = observable( { width: document.body.clientWidth, + get gridSizesConfig() { + return GridSizesConfig(this.width); + }, + get groupWidth() { + return GetGridElementWidth(this.width); + }, update() { this.width = document.body.clientWidth; } }, { - update: action.bound + update: action.bound, + gridSizesConfig: computed, + groupWidth: computed } ); } @@ -204,7 +212,7 @@ const AlertGrid = observer( ))} diff --git a/ui/src/Components/Grid/AlertGrid/index.test.js b/ui/src/Components/Grid/AlertGrid/index.test.js index 7564f533f..351726e1b 100644 --- a/ui/src/Components/Grid/AlertGrid/index.test.js +++ b/ui/src/Components/Grid/AlertGrid/index.test.js @@ -8,6 +8,7 @@ import { MockAlert, MockAlertGroup } from "__mocks__/Alerts.js"; import { AlertStore } from "Stores/AlertStore"; import { Settings } from "Stores/Settings"; import { SilenceFormStore } from "Stores/SilenceFormStore"; +import { MinWidth, GetGridElementWidth } from "./GridSize"; import { AlertGrid } from "."; let alertStore; @@ -341,60 +342,67 @@ describe("", () => { jest.runOnlyPendingTimers(); }); - it("renders 1 column with document.body.clientWidth=799", () => { - VerifyColumnCount(799, 1); - }); + // known breakpoints calculated from GridSize logic + [ + { breakpoint: 400, columns: 1 }, + { breakpoint: 820, columns: 2 }, + { breakpoint: 1245, columns: 3 }, + { breakpoint: 1680, columns: 4 }, + { breakpoint: 2125, columns: 5 }, + { breakpoint: 2580, columns: 6 }, + { breakpoint: 3045, columns: 7 }, + { breakpoint: 3520, columns: 8 }, + { breakpoint: 4005, columns: 9 }, + { breakpoint: 4500, columns: 1 } + ].map(t => + it(`renders ${t.columns} column(s) on ${t.breakpoint} breakpoint`, () => { + VerifyColumnCount(t.canvas - 1, Math.max(1, t.columns - 1)); + VerifyColumnCount(t.canvas, t.columns); + VerifyColumnCount(t.canvas + 1, t.columns); + }) + ); - it("renders 2 columns with document.body.clientWidth=800", () => { - VerifyColumnCount(800, 2); - }); + // populare screen resolutions + [ + { canvas: 640, columns: 1 }, + { canvas: 1024, columns: 2 }, + { canvas: 1280, columns: 3 }, + { canvas: 1366, columns: 3 }, + { canvas: 1440, columns: 3 }, + { canvas: 1600, columns: 3 }, + { canvas: 1680, columns: 3 }, + { canvas: 1920, columns: 4 }, + { canvas: 2048, columns: 4 }, + { canvas: 2560, columns: 5 }, + { canvas: 3840, columns: 8 } + ].map(t => + it(`renders ${t.columns} column(s) with ${t.canvas} resolution`, () => { + VerifyColumnCount(t.canvas, t.columns); + }) + ); - it("renders 2 columns with document.body.clientWidth=1399", () => { - VerifyColumnCount(1399, 2); - }); + it("renders expected number of columns for every resolution", () => { + let lastColumns = 1; + for (let i = 100; i <= 4096; i++) { + const minWidth = MinWidth(i); + const expectedColumns = Math.max(Math.floor(i / minWidth), 1); + const columns = Math.floor(i / GetGridElementWidth(i)); - it("renders 3 columns with document.body.clientWidth=1400", () => { - VerifyColumnCount(1400, 3); - }); + expect({ + resolution: i, + minWidth: minWidth, + columns: columns + }).toEqual({ + resolution: i, + minWidth: minWidth, + columns: expectedColumns + }); + expect(columns).toBeGreaterThanOrEqual(lastColumns); - it("renders 3 columns with document.body.clientWidth=2099", () => { - VerifyColumnCount(2099, 3); - }); - - it("renders 4 columns with document.body.clientWidth=2100", () => { - VerifyColumnCount(2100, 4); - }); - - it("renders 4 columns with document.body.clientWidth=2799", () => { - VerifyColumnCount(2799, 4); - }); - - it("renders 5 columns with document.body.clientWidth=2800", () => { - VerifyColumnCount(2800, 5); - }); - - it("renders 5 columns with document.body.clientWidth=3499", () => { - VerifyColumnCount(3499, 5); - }); - - it("renders 6 columns with document.body.clientWidth=1399", () => { - VerifyColumnCount(3500, 6); - }); - - it("renders 6 columns with document.body.clientWidth=4199", () => { - VerifyColumnCount(4199, 6); - }); - - it("renders 7 columns with document.body.clientWidth=1399", () => { - VerifyColumnCount(4200, 7); - }); - - it("renders 7 columns with document.body.clientWidth=5599", () => { - VerifyColumnCount(5599, 7); - }); - - it("renders 8 columns with document.body.clientWidth=5600", () => { - VerifyColumnCount(5600, 8); + // keep track of column count to verify that each incrementing resolution + // doesn't result in lower number of columns rendered + lastColumns = columns; + } }); it("viewport resize also resizes alert groups", () => { @@ -406,7 +414,7 @@ describe("", () => { .find("AlertGroup") .at(0) .props().style.width - ).toBe(1980 / 3); + ).toBe(1980 / 4); bodyWidth = 1000; // not sure how to force ReactResizeDetector to detect width change, so