From 3fbda0f35b7c39864e030f617ae667dae947e1e3 Mon Sep 17 00:00:00 2001 From: Nathan Marrs Date: Mon, 16 May 2022 10:28:19 -0700 Subject: [PATCH] Canvas: Improve constraint selection ux (#48837) --- .../canvas/editor/ConstraintSelectionBox.tsx | 183 ++++++++++++++++++ .../panel/canvas/editor/PlacementEditor.tsx | 40 ++-- 2 files changed, 211 insertions(+), 12 deletions(-) create mode 100644 public/app/plugins/panel/canvas/editor/ConstraintSelectionBox.tsx diff --git a/public/app/plugins/panel/canvas/editor/ConstraintSelectionBox.tsx b/public/app/plugins/panel/canvas/editor/ConstraintSelectionBox.tsx new file mode 100644 index 00000000000..8c815bc5c98 --- /dev/null +++ b/public/app/plugins/panel/canvas/editor/ConstraintSelectionBox.tsx @@ -0,0 +1,183 @@ +import { css } from '@emotion/css'; +import React from 'react'; + +import { GrafanaTheme2 } from '@grafana/data'; +import { useStyles2 } from '@grafana/ui'; +import { Constraint, HorizontalConstraint, VerticalConstraint } from 'app/features/canvas'; + +interface Props { + onVerticalConstraintChange: (v: VerticalConstraint) => void; + onHorizontalConstraintChange: (h: HorizontalConstraint) => void; + currentConstraints: Constraint; +} + +export const ConstraintSelectionBox = ({ + onVerticalConstraintChange, + onHorizontalConstraintChange, + currentConstraints, +}: Props) => { + const styles = useStyles2(getStyles(currentConstraints)); + + const onClickTopConstraint = () => { + onVerticalConstraintChange(VerticalConstraint.Top); + }; + + const onClickBottomConstraint = () => { + onVerticalConstraintChange(VerticalConstraint.Bottom); + }; + + const onClickVerticalCenterConstraint = () => { + onVerticalConstraintChange(VerticalConstraint.Center); + }; + + const onClickLeftConstraint = () => { + onHorizontalConstraintChange(HorizontalConstraint.Left); + }; + + const onClickRightConstraint = () => { + onHorizontalConstraintChange(HorizontalConstraint.Right); + }; + + const onClickHorizontalCenterConstraint = () => { + onHorizontalConstraintChange(HorizontalConstraint.Center); + }; + + return ( + + + + + + + + + + + + + + + + + + + ); +}; + +const getStyles = (currentConstraints: Constraint) => (theme: GrafanaTheme2) => { + const HOVER_COLOR = '#daebf7'; + const HOVER_OPACITY = '0.6'; + const SELECTED_COLOR = '#0d99ff'; + + const selectionBoxColor = theme.isDark ? '#ffffff' : '#000000'; + + return { + constraintHover: css` + &:hover { + fill: ${HOVER_COLOR}; + fill-opacity: ${HOVER_OPACITY}; + } + `, + topConstraint: css` + ${currentConstraints.vertical === VerticalConstraint.Top + ? `width: 92pt; x: 1085; fill: ${SELECTED_COLOR};` + : `fill: ${selectionBoxColor};`} + `, + bottomConstraint: css` + ${currentConstraints.vertical === VerticalConstraint.Bottom + ? `width: 92pt; x: 1085; fill: ${SELECTED_COLOR};` + : `fill: ${selectionBoxColor};`} + `, + leftConstraint: css` + ${currentConstraints.horizontal === HorizontalConstraint.Left + ? `height: 92pt; y: 1014; fill: ${SELECTED_COLOR};` + : `fill: ${selectionBoxColor};`} + `, + rightConstraint: css` + ${currentConstraints.horizontal === HorizontalConstraint.Right + ? `height: 92pt; y: 1014; fill: ${SELECTED_COLOR};` + : `fill: ${selectionBoxColor};`} + `, + horizontalCenterConstraint: css` + ${currentConstraints.horizontal === HorizontalConstraint.Center + ? `height: 92pt; y: 1014; fill: ${SELECTED_COLOR};` + : `fill: ${selectionBoxColor};`} + `, + verticalCenterConstraint: css` + ${currentConstraints.vertical === VerticalConstraint.Center + ? `width: 92pt; x: 1085; fill: ${SELECTED_COLOR};` + : `fill: ${selectionBoxColor};`} + `, + box: css` + fill: ${selectionBoxColor}; + `, + }; +}; diff --git a/public/app/plugins/panel/canvas/editor/PlacementEditor.tsx b/public/app/plugins/panel/canvas/editor/PlacementEditor.tsx index b64564f6dc4..7916ef11743 100644 --- a/public/app/plugins/panel/canvas/editor/PlacementEditor.tsx +++ b/public/app/plugins/panel/canvas/editor/PlacementEditor.tsx @@ -3,12 +3,13 @@ import { useObservable } from 'react-use'; import { Subject } from 'rxjs'; import { SelectableValue, StandardEditorProps } from '@grafana/data'; -import { Field, InlineField, InlineFieldRow, Select, VerticalGroup } from '@grafana/ui'; +import { Field, HorizontalGroup, InlineField, InlineFieldRow, Select, VerticalGroup } from '@grafana/ui'; import { HorizontalConstraint, Placement, VerticalConstraint } from 'app/features/canvas'; import { NumberInput } from 'app/features/dimensions/editors/NumberInput'; import { PanelOptions } from '../models.gen'; +import { ConstraintSelectionBox } from './ConstraintSelectionBox'; import { CanvasEditorOptions } from './elementEditor'; const places: Array = ['top', 'left', 'bottom', 'right', 'width', 'height']; @@ -46,15 +47,23 @@ export const PlacementEditor: FC) => { - element.options.constraint!.horizontal = h.value; + const onHorizontalConstraintSelect = (h: SelectableValue) => { + onHorizontalConstraintChange(h.value!); + }; + + const onHorizontalConstraintChange = (h: HorizontalConstraint) => { + element.options.constraint!.horizontal = h; element.setPlacementFromConstraint(); settings.scene.revId++; settings.scene.save(true); }; - const onVerticalConstraintChange = (v: SelectableValue) => { - element.options.constraint!.vertical = v.value; + const onVerticalConstraintSelect = (v: SelectableValue) => { + onVerticalConstraintChange(v.value!); + }; + + const onVerticalConstraintChange = (v: VerticalConstraint) => { + element.options.constraint!.vertical = v; element.setPlacementFromConstraint(); settings.scene.revId++; settings.scene.save(true); @@ -68,14 +77,21 @@ export const PlacementEditor: FC - - + - + + + +