From 6cb7d959165b9fd34844d8fda313bf3bd65c4d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 11 Apr 2020 16:07:18 +0200 Subject: [PATCH] Components: IconButton (#23510) * IconButton: New component to share pointer, size & hover style for icon buttons * Progress * IconButton: new component * Think I am done * Updated snapshots * Do not like the black button reverting that, and not the plus-circle changed to plus * fixed test * fixed e2e test * Fixed ts issue --- packages/grafana-data/src/types/theme.ts | 1 + .../src/components/Button/Button.tsx | 34 +++-- .../CallToActionCard.story.tsx | 2 +- .../components/DataLinks/DataLinksEditor.tsx | 2 +- .../CustomHeadersSettings.test.tsx | 2 +- .../CustomHeadersSettings.tsx | 6 +- .../src/components/Forms/commonStyles.ts | 32 ++--- .../grafana-ui/src/components/Icon/Icon.tsx | 28 ++-- .../IconButton/IconButton.story.tsx | 66 ++++++++++ .../src/components/IconButton/IconButton.tsx | 121 ++++++++++++++++++ .../grafana-ui/src/components/Modal/Modal.tsx | 8 +- .../src/components/Modal/getModalStyles.ts | 11 +- .../__snapshots__/TimePicker.test.tsx.snap | 2 + .../components/Tooltip/PopoverController.tsx | 19 ++- .../components/ValuePicker/ValuePicker.tsx | 2 +- packages/grafana-ui/src/components/index.ts | 1 + .../src/themes/_variables.dark.scss.tmpl.ts | 4 +- .../src/themes/_variables.light.scss.tmpl.ts | 4 +- packages/grafana-ui/src/themes/dark.ts | 12 +- packages/grafana-ui/src/themes/light.ts | 9 +- packages/grafana-ui/src/types/icon.ts | 2 +- .../core/components/BackButton/BackButton.tsx | 79 ++---------- .../core/components/PageHeader/PageHeader.tsx | 2 +- .../QueryOperationAction.tsx | 36 +++--- .../manage_dashboards/manage_dashboards.html | 2 +- .../dashboard/components/DashNav/DashNav.tsx | 2 +- .../DashboardSettings/DashboardSettings.tsx | 2 +- .../components/Inspector/InspectHeader.tsx | 25 +--- .../components/PanelEditor/PanelEditor.tsx | 4 +- .../explore/RichHistory/RichHistoryCard.tsx | 16 +-- .../elasticsearch/configuration/DataLinks.tsx | 2 +- .../plugins/panel/table/column_options.html | 2 +- public/sass/_variables.dark.generated.scss | 2 +- public/sass/_variables.light.generated.scss | 4 +- public/sass/components/_navbar.scss | 2 +- 35 files changed, 351 insertions(+), 197 deletions(-) create mode 100644 packages/grafana-ui/src/components/IconButton/IconButton.story.tsx create mode 100644 packages/grafana-ui/src/components/IconButton/IconButton.tsx diff --git a/packages/grafana-data/src/types/theme.ts b/packages/grafana-data/src/types/theme.ts index 192cf1e1562..1d636876ff7 100644 --- a/packages/grafana-data/src/types/theme.ts +++ b/packages/grafana-data/src/types/theme.ts @@ -214,6 +214,7 @@ export interface GrafanaTheme extends GrafanaThemeCommons { // TODO: move to background section bodyBg: string; pageBg: string; + pageHeaderBg: string; headingColor: string; pageHeaderBorder: string; diff --git a/packages/grafana-ui/src/components/Button/Button.tsx b/packages/grafana-ui/src/components/Button/Button.tsx index b16ea804492..55721561ce3 100644 --- a/packages/grafana-ui/src/components/Button/Button.tsx +++ b/packages/grafana-ui/src/components/Button/Button.tsx @@ -1,7 +1,7 @@ import React, { AnchorHTMLAttributes, ButtonHTMLAttributes, useContext } from 'react'; import { css, cx } from 'emotion'; import tinycolor from 'tinycolor2'; -import { selectThemeVariant, stylesFactory, ThemeContext } from '../../themes'; +import { stylesFactory, ThemeContext } from '../../themes'; import { IconName } from '../../types/icon'; import { getFocusStyle, getPropertiesForButtonSize } from '../Forms/commonStyles'; import { GrafanaTheme } from '@grafana/data'; @@ -25,24 +25,17 @@ const buttonVariantStyles = (from: string, to: string, textColor: string) => css const getPropertiesForVariant = (theme: GrafanaTheme, variant: ButtonVariant) => { switch (variant) { case 'secondary': - const from = selectThemeVariant({ light: theme.colors.gray7, dark: theme.colors.gray10 }, theme.type) as string; - const to = selectThemeVariant( - { - light: tinycolor(from) + const from = theme.isLight ? theme.colors.gray7 : theme.colors.gray15; + const to = theme.isLight + ? tinycolor(from) .darken(5) - .toString(), - dark: theme.colors.gray05, - }, - theme.type - ) as string; - + .toString() + : tinycolor(from) + .lighten(4) + .toString(); return { - borderColor: selectThemeVariant({ light: theme.colors.gray85, dark: theme.colors.gray25 }, theme.type), - background: buttonVariantStyles( - from, - to, - selectThemeVariant({ light: theme.colors.gray25, dark: theme.colors.gray4 }, theme.type) as string - ), + borderColor: theme.isLight ? theme.colors.gray85 : theme.colors.gray25, + background: buttonVariantStyles(from, to, theme.isLight ? theme.colors.gray25 : theme.colors.gray4), }; case 'destructive': @@ -74,12 +67,13 @@ const getPropertiesForVariant = (theme: GrafanaTheme, variant: ButtonVariant) => export interface StyleProps { theme: GrafanaTheme; size: ComponentSize; + icon?: IconName; variant: ButtonVariant; textAndIcon?: boolean; } -export const getButtonStyles = stylesFactory(({ theme, size, variant }: StyleProps) => { - const { padding, fontSize, height } = getPropertiesForButtonSize(theme, size); +export const getButtonStyles = stylesFactory(({ theme, size, variant, icon }: StyleProps) => { + const { padding, fontSize, height } = getPropertiesForButtonSize(theme, size, icon); const { background, borderColor, variantStyles } = getPropertiesForVariant(theme, variant); return { @@ -146,6 +140,7 @@ export const Button = React.forwardRef( theme, size: otherProps.size || 'md', variant: variant || 'primary', + icon, }); return ( @@ -168,6 +163,7 @@ export const LinkButton = React.forwardRef( theme, size: otherProps.size || 'md', variant: variant || 'primary', + icon, }); return ( diff --git a/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.story.tsx b/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.story.tsx index 4927b3e6868..e2672caac6c 100644 --- a/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.story.tsx +++ b/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.story.tsx @@ -12,7 +12,7 @@ CallToActionCardStories.add('default', () => { const ctaElements: { [key: string]: JSX.Element } = { custom:

This is just H1 tag, you can any component as CTA element

, button: ( - ), diff --git a/packages/grafana-ui/src/components/DataLinks/DataLinksEditor.tsx b/packages/grafana-ui/src/components/DataLinks/DataLinksEditor.tsx index 73b6a6a1007..dfbfdda6644 100644 --- a/packages/grafana-ui/src/components/DataLinks/DataLinksEditor.tsx +++ b/packages/grafana-ui/src/components/DataLinks/DataLinksEditor.tsx @@ -73,7 +73,7 @@ export const DataLinksEditor: FC = React.memo( )} {(!value || (value && value.length < (maxLinks || Infinity))) && ( - )} diff --git a/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.test.tsx b/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.test.tsx index 8bb9416b02a..f12ef86df39 100644 --- a/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.test.tsx +++ b/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.test.tsx @@ -57,7 +57,7 @@ describe('Render', () => { }, }, }); - const removeButton = wrapper.find('Button').find({ variant: 'destructive' }); + const removeButton = wrapper.find('Button').at(1); removeButton.simulate('click', { preventDefault: () => {} }); expect(wrapper.find('FormField').exists()).toBeFalsy(); expect(wrapper.find('SecretFormField').exists()).toBeFalsy(); diff --git a/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.tsx b/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.tsx index 74a324336d6..19a89efd121 100644 --- a/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.tsx +++ b/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.tsx @@ -76,7 +76,7 @@ const CustomHeaderRow: React.FC = ({ header, onBlur, onCha onChange={e => onChange({ ...header, value: e.target.value })} onBlur={onBlur} /> - @@ -203,12 +203,12 @@ export class CustomHeadersSettings extends PureComponent {
diff --git a/packages/grafana-ui/src/components/Forms/commonStyles.ts b/packages/grafana-ui/src/components/Forms/commonStyles.ts index 806a4decb13..e5675cd691a 100644 --- a/packages/grafana-ui/src/components/Forms/commonStyles.ts +++ b/packages/grafana-ui/src/components/Forms/commonStyles.ts @@ -1,6 +1,7 @@ import { css } from 'emotion'; import { GrafanaTheme } from '@grafana/data'; import { ComponentSize } from '../../types/size'; +import { IconName } from '../../types'; export const getFocusCss = (theme: GrafanaTheme) => ` outline: 2px dotted transparent; @@ -90,34 +91,29 @@ export const inputSizesPixels = (size: string) => { } }; -export const getPropertiesForButtonSize = (theme: GrafanaTheme, size: ComponentSize) => { +export const getPropertiesForButtonSize = (theme: GrafanaTheme, size: ComponentSize, icon?: IconName) => { + const { spacing, typography, height } = theme; + switch (size) { case 'sm': return { - padding: `0 ${theme.spacing.sm}`, - fontSize: theme.typography.size.sm, - height: theme.height.sm, - }; - - case 'md': - return { - padding: `0 ${theme.spacing.md}`, - fontSize: theme.typography.size.md, - height: `${theme.spacing.formButtonHeight}px`, + padding: `0 ${spacing.sm}`, + fontSize: typography.size.sm, + height: height.sm, }; case 'lg': return { - padding: `0 ${theme.spacing.lg}`, - fontSize: theme.typography.size.lg, - height: theme.height.lg, + padding: `0 ${spacing.lg} 0 ${icon ? spacing.md : spacing.lg}`, + fontSize: typography.size.lg, + height: height.lg, }; - + case 'md': default: return { - padding: `0 ${theme.spacing.md}`, - fontSize: theme.typography.size.base, - height: theme.height.md, + padding: `0 ${spacing.md} 0 ${icon ? spacing.sm : spacing.md}`, + fontSize: typography.size.md, + height: height.md, }; } }; diff --git a/packages/grafana-ui/src/components/Icon/Icon.tsx b/packages/grafana-ui/src/components/Icon/Icon.tsx index 8349be35327..0cbd9814b12 100644 --- a/packages/grafana-ui/src/components/Icon/Icon.tsx +++ b/packages/grafana-ui/src/components/Icon/Icon.tsx @@ -4,7 +4,6 @@ import { GrafanaTheme, toPascalCase } from '@grafana/data'; import { stylesFactory } from '../../themes/stylesFactory'; import { useTheme } from '../../themes/ThemeContext'; import { IconName, IconType, IconSize } from '../../types/icon'; -import { ComponentSize } from '../../types/size'; //@ts-ignore import * as DefaultIcon from '@iconscout/react-unicons'; import * as MonoIcon from './assets'; @@ -36,7 +35,7 @@ export const Icon = React.forwardRef( ({ size = 'md', type = 'default', name, className, style, ...divElementProps }, ref) => { const theme = useTheme(); const styles = getIconStyles(theme); - const svgSize = getSvgSize(size, theme); + const svgSize = getSvgSize(size); /* Temporary solution to display also font awesome icons */ const isFontAwesome = name?.includes('fa-'); @@ -72,14 +71,21 @@ export const Icon = React.forwardRef( Icon.displayName = 'Icon'; /* Transform string with px to number and add 2 pxs as path in svg is 2px smaller */ -const getSvgSize = (size: ComponentSize | 'xl' | 'xxl', theme: GrafanaTheme) => { - let svgSize; - if (size === 'xl') { - svgSize = Number(theme.typography.heading.h1.slice(0, -2)); - } else if (size === 'xxl') { - svgSize = Number(theme.height.lg.slice(0, -2)); - } else { - svgSize = Number(theme.typography.size[size].slice(0, -2)) + 2; +export const getSvgSize = (size: IconSize) => { + switch (size) { + case 'xs': + return 12; + case 'sm': + return 14; + case 'md': + return 16; + case 'lg': + return 18; + case 'xl': + return 28; + case 'xxl': + return 36; + case 'xxxl': + return 48; } - return svgSize; }; diff --git a/packages/grafana-ui/src/components/IconButton/IconButton.story.tsx b/packages/grafana-ui/src/components/IconButton/IconButton.story.tsx new file mode 100644 index 00000000000..a4a238ae7c5 --- /dev/null +++ b/packages/grafana-ui/src/components/IconButton/IconButton.story.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { css } from 'emotion'; +import { IconButton } from './IconButton'; +import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; +import { useTheme } from '../../themes/ThemeContext'; +import { GrafanaTheme } from '@grafana/data'; +import { IconSize, IconName } from '../../types'; + +export default { + title: 'General/IconButton', + component: IconButton, + decorators: [withCenteredStory], + parameters: { + docs: {}, + }, +}; + +export const simple = () => { + const theme = useTheme(); + + return ( +
+ {renderScenario('body', theme, ['sm', 'md', 'lg', 'xl', 'xxl'], ['search', 'trash-alt', 'arrow-left', 'times'])} + {renderScenario('panel', theme, ['sm', 'md', 'lg', 'xl', 'xxl'], ['search', 'trash-alt', 'arrow-left', 'times'])} + {renderScenario('header', theme, ['sm', 'md', 'lg', 'xl', 'xxl'], ['search', 'trash-alt', 'arrow-left', 'times'])} +
+ ); +}; + +function renderScenario(surface: string, theme: GrafanaTheme, sizes: IconSize[], icons: IconName[]) { + let bg: string = 'red'; + + switch (surface) { + case 'body': + bg = theme.colors.bodyBg; + break; + case 'panel': + bg = theme.colors.pageBg; + break; + case 'header': { + bg = theme.colors.pageHeaderBg; + } + } + + return ( +
+ {icons.map(icon => { + return sizes.map(size => ( + + + + )); + })} +
+ ); +} diff --git a/packages/grafana-ui/src/components/IconButton/IconButton.tsx b/packages/grafana-ui/src/components/IconButton/IconButton.tsx new file mode 100644 index 00000000000..417f1e3f149 --- /dev/null +++ b/packages/grafana-ui/src/components/IconButton/IconButton.tsx @@ -0,0 +1,121 @@ +import React from 'react'; +import { Icon, getSvgSize } from '../Icon/Icon'; +import { IconName, IconSize, IconType } from '../../types/icon'; +import { stylesFactory } from '../../themes/stylesFactory'; +import { css, cx } from 'emotion'; +import { useTheme } from '../../themes/ThemeContext'; +import { GrafanaTheme } from '@grafana/data'; +import { Tooltip } from '../Tooltip/Tooltip'; +import { TooltipPlacement } from '../Tooltip/PopoverController'; + +export interface Props extends React.ButtonHTMLAttributes { + name: IconName; + size?: IconSize; + /** Need this to change hover effect based on what surface it is on */ + surface?: SurfaceType; + iconType?: IconType; + tooltip?: string; + tooltipPlacement?: TooltipPlacement; +} + +type SurfaceType = 'body' | 'panel' | 'header'; + +export const IconButton = React.forwardRef( + ({ name, size = 'md', surface = 'panel', iconType, tooltip, tooltipPlacement, className, ...restProps }, ref) => { + const theme = useTheme(); + const styles = getStyles(theme, surface, size); + + const button = ( + + ); + + if (tooltip) { + return ( + + {button} + + ); + } + + return button; + } +); + +function getHoverColor(theme: GrafanaTheme, surface: SurfaceType): string { + switch (surface) { + case 'body': + return theme.isLight ? theme.colors.gray95 : theme.colors.gray15; + case 'panel': + return theme.isLight ? theme.colors.gray6 : theme.colors.gray25; + case 'header': + return theme.isLight ? theme.colors.gray85 : theme.colors.gray25; + } +} + +const getStyles = stylesFactory((theme: GrafanaTheme, surface: SurfaceType, size: IconSize) => { + const hoverColor = getHoverColor(theme, surface); + const pixelSize = getSvgSize(size); + + return { + button: css` + width: ${pixelSize}px; + height: ${pixelSize}px; + background: transparent; + border: none; + padding: 0; + margin: 0; + outline: none; + box-shadow: none; + display: inline-flex; + align-items: center; + justify-content: center; + position: relative; + z-index: 0; + margin-right: ${theme.spacing.xs}; + + &[disabled], + &:disabled { + cursor: not-allowed; + opacity: 0.65; + box-shadow: none; + } + + &:before { + content: ''; + display: block; + opacity: 1; + position: absolute; + transition-duration: 0.2s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + z-index: -1; + bottom: -8px; + left: -8px; + right: -8px; + top: -8px; + background: none; + border-radius: 50%; + box-sizing: border-box; + transform: scale(0); + transition-property: transform, opacity; + } + + &:hover { + color: ${theme.colors.linkHover}; + + &:before { + background-color: ${hoverColor}; + border: none; + box-shadow: none; + opacity: 1; + transform: scale(0.8); + } + } + `, + icon: css` + margin-bottom: 0; + display: flex; + `, + }; +}); diff --git a/packages/grafana-ui/src/components/Modal/Modal.tsx b/packages/grafana-ui/src/components/Modal/Modal.tsx index e0e956a36b7..3ed5b92b743 100644 --- a/packages/grafana-ui/src/components/Modal/Modal.tsx +++ b/packages/grafana-ui/src/components/Modal/Modal.tsx @@ -6,7 +6,7 @@ import { IconName } from '../../types'; import { Themeable } from '../../types'; import { getModalStyles } from './getModalStyles'; import { ModalHeader } from './ModalHeader'; -import { Icon } from '../Icon/Icon'; +import { IconButton } from '../IconButton/IconButton'; interface Props extends Themeable { icon?: IconName; @@ -50,9 +50,9 @@ export class UnthemedModal extends React.PureComponent {
{typeof title === 'string' ? this.renderDefaultHeader(title) : title} - - - +
+ +
{this.props.children}
diff --git a/packages/grafana-ui/src/components/Modal/getModalStyles.ts b/packages/grafana-ui/src/components/Modal/getModalStyles.ts index d36f653640c..5b7dc2c269e 100644 --- a/packages/grafana-ui/src/components/Modal/getModalStyles.ts +++ b/packages/grafana-ui/src/components/Modal/getModalStyles.ts @@ -37,10 +37,11 @@ export const getModalStyles = stylesFactory((theme: GrafanaTheme) => { opacity: 0.7; `, modalHeader: css` - background: ${theme.background.pageHeader}; + background: ${theme.colors.pageHeaderBg}; box-shadow: ${theme.shadow.pageHeader}; border-bottom: 1px solid ${theme.colors.pageHeaderBorder}; display: flex; + height: 42px; `, modalHeaderTitle: css` font-size: ${theme.typography.heading.h3}; @@ -55,8 +56,12 @@ export const getModalStyles = stylesFactory((theme: GrafanaTheme) => { } `, modalHeaderClose: css` - margin-left: auto; - padding: 9px ${theme.spacing.d}; + height: 100%; + display: flex; + align-items: center; + flex-grow: 1; + justify-content: flex-end; + padding-right: ${theme.spacing.sm}; `, modalContent: css` padding: calc(${theme.spacing.d} * 2); diff --git a/packages/grafana-ui/src/components/TimePicker/__snapshots__/TimePicker.test.tsx.snap b/packages/grafana-ui/src/components/TimePicker/__snapshots__/TimePicker.test.tsx.snap index b2cd46f7f90..15fe0761204 100644 --- a/packages/grafana-ui/src/components/TimePicker/__snapshots__/TimePicker.test.tsx.snap +++ b/packages/grafana-ui/src/components/TimePicker/__snapshots__/TimePicker.test.tsx.snap @@ -157,6 +157,7 @@ exports[`TimePicker renders buttons correctly 1`] = ` "orange": "#eb7b18", "orangeDark": "#ff780a", "pageBg": "#141619", + "pageHeaderBg": "#202226", "pageHeaderBorder": "#202226", "panelBg": "#141619", "panelBorder": "#202226", @@ -472,6 +473,7 @@ exports[`TimePicker renders content correctly after beeing open 1`] = ` "orange": "#eb7b18", "orangeDark": "#ff780a", "pageBg": "#141619", + "pageHeaderBg": "#202226", "pageHeaderBorder": "#202226", "panelBg": "#141619", "panelBorder": "#202226", diff --git a/packages/grafana-ui/src/components/Tooltip/PopoverController.tsx b/packages/grafana-ui/src/components/Tooltip/PopoverController.tsx index a76f89c12ea..4adcde79bde 100644 --- a/packages/grafana-ui/src/components/Tooltip/PopoverController.tsx +++ b/packages/grafana-ui/src/components/Tooltip/PopoverController.tsx @@ -7,11 +7,28 @@ import { PopoverContent } from './Tooltip'; export interface UsingPopperProps { show?: boolean; - placement?: PopperJS.Placement; + placement?: TooltipPlacement; content: PopoverContent; children: JSX.Element; } +export type TooltipPlacement = + | 'auto-start' + | 'auto' + | 'auto-end' + | 'top-start' + | 'top' + | 'top-end' + | 'right-start' + | 'right' + | 'right-end' + | 'bottom-end' + | 'bottom' + | 'bottom-start' + | 'left-end' + | 'left' + | 'left-start'; + type PopperControllerRenderProp = ( showPopper: () => void, hidePopper: () => void, diff --git a/packages/grafana-ui/src/components/ValuePicker/ValuePicker.tsx b/packages/grafana-ui/src/components/ValuePicker/ValuePicker.tsx index f54e14302b8..5244c99fe29 100644 --- a/packages/grafana-ui/src/components/ValuePicker/ValuePicker.tsx +++ b/packages/grafana-ui/src/components/ValuePicker/ValuePicker.tsx @@ -31,7 +31,7 @@ export function ValuePicker({ const [isPicking, setIsPicking] = useState(false); const buttonEl = ( - ); diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index 74c5e522e0a..074415d67e1 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -1,4 +1,5 @@ export { Icon } from './Icon/Icon'; +export { IconButton } from './IconButton/IconButton'; export { ConfirmButton } from './ConfirmButton/ConfirmButton'; export { DeleteButton } from './ConfirmButton/DeleteButton'; export { Tooltip, PopoverContent } from './Tooltip/Tooltip'; diff --git a/packages/grafana-ui/src/themes/_variables.dark.scss.tmpl.ts b/packages/grafana-ui/src/themes/_variables.dark.scss.tmpl.ts index cbaf7740d40..f935df4412f 100644 --- a/packages/grafana-ui/src/themes/_variables.dark.scss.tmpl.ts +++ b/packages/grafana-ui/src/themes/_variables.dark.scss.tmpl.ts @@ -126,9 +126,9 @@ $panel-header-hover-bg: ${theme.colors.gray15}; $panel-corner: $panel-bg; // page header -$page-header-bg: ${theme.colors.gray15}; +$page-header-bg: ${theme.colors.pageHeaderBg}; $page-header-shadow: inset 0px -4px 14px $dark-3; -$page-header-border-color: $dark-9; +$page-header-border-color: ${theme.colors.pageHeaderBorder}; $divider-border-color: $gray-1; diff --git a/packages/grafana-ui/src/themes/_variables.light.scss.tmpl.ts b/packages/grafana-ui/src/themes/_variables.light.scss.tmpl.ts index 351a518dee9..b20adbe4d3b 100644 --- a/packages/grafana-ui/src/themes/_variables.light.scss.tmpl.ts +++ b/packages/grafana-ui/src/themes/_variables.light.scss.tmpl.ts @@ -118,9 +118,9 @@ $panel-header-hover-bg: $gray-6; $panel-corner: $gray-4; // Page header -$page-header-bg: linear-gradient(90deg, $white, ${theme.colors.gray95}); +$page-header-bg: ${theme.colors.pageHeaderBg}; $page-header-shadow: inset 0px -3px 10px $gray-6; -$page-header-border-color: $gray-4; +$page-header-border-color: ${theme.colors.pageHeaderBorder}; $divider-border-color: $gray-2; diff --git a/packages/grafana-ui/src/themes/dark.ts b/packages/grafana-ui/src/themes/dark.ts index 1a637d80745..6f14a8a4045 100644 --- a/packages/grafana-ui/src/themes/dark.ts +++ b/packages/grafana-ui/src/themes/dark.ts @@ -61,8 +61,7 @@ const darkTheme: GrafanaTheme = { online: basicColors.greenBase, warn: '#f79520', critical: basicColors.redBase, - bodyBg: basicColors.gray05, - pageBg: basicColors.gray10, + body: basicColors.gray4, text: basicColors.gray85, textStrong: basicColors.white, @@ -74,8 +73,15 @@ const darkTheme: GrafanaTheme = { linkHover: basicColors.white, linkExternal: basicColors.blue, headingColor: basicColors.gray4, - pageHeaderBorder: basicColors.gray15, + + // Backgrounds + bodyBg: basicColors.gray05, + pageBg: basicColors.gray10, + pageHeaderBg: basicColors.gray15, panelBg: basicColors.gray10, + + // Borders + pageHeaderBorder: basicColors.gray15, panelBorder: basicColors.gray15, // Next-gen forms functional colors diff --git a/packages/grafana-ui/src/themes/light.ts b/packages/grafana-ui/src/themes/light.ts index b83d06b0e52..633764f3887 100644 --- a/packages/grafana-ui/src/themes/light.ts +++ b/packages/grafana-ui/src/themes/light.ts @@ -62,8 +62,12 @@ const lightTheme: GrafanaTheme = { online: basicColors.greenShade, warn: '#f79520', critical: basicColors.redShade, + + // Backgrounds bodyBg: basicColors.gray7, pageBg: basicColors.white, + pageHeaderBg: basicColors.gray95, + panelBg: basicColors.white, // Text colors body: basicColors.gray1, @@ -79,11 +83,10 @@ const lightTheme: GrafanaTheme = { linkHover: basicColors.dark1, linkExternal: basicColors.blueLight, headingColor: basicColors.gray1, - pageHeaderBorder: basicColors.gray4, - // panel - panelBg: basicColors.white, + // Borders panelBorder: basicColors.gray95, + pageHeaderBorder: basicColors.gray4, // Next-gen forms functional colors formLabel: basicColors.gray33, diff --git a/packages/grafana-ui/src/types/icon.ts b/packages/grafana-ui/src/types/icon.ts index a1a32f4a5c1..58cc1bab5a7 100644 --- a/packages/grafana-ui/src/types/icon.ts +++ b/packages/grafana-ui/src/types/icon.ts @@ -1,6 +1,6 @@ import { ComponentSize } from './size'; export type IconType = 'mono' | 'default'; -export type IconSize = ComponentSize | 'xl' | 'xxl'; +export type IconSize = ComponentSize | 'xl' | 'xxl' | 'xxxl'; export type IconName = | 'fa fa-fw fa-unlock' diff --git a/public/app/core/components/BackButton/BackButton.tsx b/public/app/core/components/BackButton/BackButton.tsx index d686c996ea4..e4d1e5068b0 100644 --- a/public/app/core/components/BackButton/BackButton.tsx +++ b/public/app/core/components/BackButton/BackButton.tsx @@ -1,74 +1,23 @@ import React, { ButtonHTMLAttributes } from 'react'; -import { css } from 'emotion'; -import { GrafanaTheme } from '@grafana/data'; -import { selectThemeVariant, stylesFactory, Tooltip, useTheme } from '@grafana/ui'; +import { IconButton } from '@grafana/ui'; import { e2e } from '@grafana/e2e'; -export type Props = ButtonHTMLAttributes; - -export const BackButton: React.FC = props => { - const theme = useTheme(); - const styles = getStyles(theme); +export interface Props extends ButtonHTMLAttributes { + surface: 'body' | 'panel'; +} +export const BackButton: React.FC = ({ surface, onClick }) => { return ( - - - + ); }; BackButton.displayName = 'BackButton'; - -const getStyles = stylesFactory((theme: GrafanaTheme) => { - const hoverColor = selectThemeVariant({ dark: theme.colors.gray15, light: theme.colors.gray85 }, theme.type); - - return { - wrapper: css` - background: transparent; - border: none; - padding: 0; - margin: 0; - outline: none; - box-shadow: none; - display: flex; - align-items: center; - justify-content: center; - position: relative; - - &:before { - content: ''; - display: block; - opacity: 1; - position: absolute; - transition-duration: 0.2s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - z-index: -1; - bottom: -10px; - left: -10px; - right: -10px; - top: -10px; - background: none; - border-radius: 50%; - box-sizing: border-box; - transform: scale(0); - transition-property: transform, opacity; - } - - .gicon { - font-size: 26px; - } - - &:hover { - &:before { - background-color: ${hoverColor}; - border: none; - box-shadow: none; - opacity: 1; - transform: scale(0.8); - } - } - `, - }; -}); diff --git a/public/app/core/components/PageHeader/PageHeader.tsx b/public/app/core/components/PageHeader/PageHeader.tsx index 57a44828540..da8dfb2b95c 100644 --- a/public/app/core/components/PageHeader/PageHeader.tsx +++ b/public/app/core/components/PageHeader/PageHeader.tsx @@ -126,7 +126,7 @@ export default class PageHeader extends React.Component { return (
- {main.icon && } + {main.icon && } {main.img && } diff --git a/public/app/core/components/QueryOperationRow/QueryOperationAction.tsx b/public/app/core/components/QueryOperationRow/QueryOperationAction.tsx index 6767503734e..5ea578105f7 100644 --- a/public/app/core/components/QueryOperationRow/QueryOperationAction.tsx +++ b/public/app/core/components/QueryOperationRow/QueryOperationAction.tsx @@ -1,6 +1,6 @@ -import { Icon, IconName, stylesFactory, useTheme } from '@grafana/ui'; +import { IconName, IconButton, stylesFactory, useTheme } from '@grafana/ui'; import React from 'react'; -import { css, cx } from 'emotion'; +import { css } from 'emotion'; import { GrafanaTheme } from '@grafana/data'; interface QueryOperationActionProps { @@ -12,7 +12,8 @@ interface QueryOperationActionProps { export const QueryOperationAction: React.FC = ({ icon, disabled, title, ...otherProps }) => { const theme = useTheme(); - const styles = getQueryOperationActionStyles(theme, !!disabled); + const styles = getStyles(theme); + const onClick = (e: React.MouseEvent) => { if (!disabled) { otherProps.onClick(e); @@ -20,26 +21,23 @@ export const QueryOperationAction: React.FC = ({ icon }; return (
- +
); }; -const getQueryOperationActionStyles = stylesFactory((theme: GrafanaTheme, disabled: boolean) => { +QueryOperationAction.displayName = 'QueryOperationAction'; + +const getStyles = stylesFactory((theme: GrafanaTheme) => { return { - icon: cx( - !disabled && - css` - cursor: pointer; - color: ${theme.colors.textWeak}; - `, - disabled && - css` - color: ${theme.colors.gray25}; - cursor: disabled; - ` - ), + icon: css` + color: ${theme.colors.textWeak}; + `, }; }); - -QueryOperationAction.displayName = 'QueryOperationAction'; diff --git a/public/app/core/components/manage_dashboards/manage_dashboards.html b/public/app/core/components/manage_dashboards/manage_dashboards.html index 4356b16fd6b..40ef7c1991c 100644 --- a/public/app/core/components/manage_dashboards/manage_dashboards.html +++ b/public/app/core/components/manage_dashboards/manage_dashboards.html @@ -107,7 +107,7 @@
{ renderBackButton() { return (
- +
); } diff --git a/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx index 7ec39850add..133638646f1 100644 --- a/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx +++ b/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx @@ -50,7 +50,7 @@ export class DashboardSettings extends PureComponent {
- +
{haveFolder &&
{folderTitle} /
} diff --git a/public/app/features/dashboard/components/Inspector/InspectHeader.tsx b/public/app/features/dashboard/components/Inspector/InspectHeader.tsx index df808220d7c..752461d28a1 100644 --- a/public/app/features/dashboard/components/Inspector/InspectHeader.tsx +++ b/public/app/features/dashboard/components/Inspector/InspectHeader.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react'; import { css } from 'emotion'; -import { Icon, stylesFactory, Tab, TabsBar, useTheme } from '@grafana/ui'; +import { stylesFactory, Tab, TabsBar, useTheme, IconButton } from '@grafana/ui'; import { GrafanaTheme, SelectableValue, PanelData, getValueFormat, formattedValueToString } from '@grafana/data'; import { InspectTab } from './PanelInspector'; import { PanelModel } from '../../state'; @@ -32,12 +32,8 @@ export const InspectHeader: FC = ({ return (
-
- -
-
- -
+ +

{panel.title}

@@ -66,27 +62,18 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => { background-color: ${headerBackground}; z-index: 1; flex-grow: 0; + padding-top: ${theme.spacing.sm}; `, actions: css` + position: absolute; display: flex; align-items: baseline; justify-content: space-between; - margin: ${theme.spacing.md}; + right: ${theme.spacing.sm}; `, tabsBar: css` padding-left: ${theme.spacing.md}; `, - iconWrapper: css` - cursor: pointer; - width: 25px; - height: 100%; - display: flex; - flex-shrink: 0; - justify-content: center; - `, - icon: css` - font-size: ${theme.typography.size.lg}; - `, titleWrapper: css` margin-bottom: ${theme.spacing.lg}; padding: ${theme.spacing.sm} ${theme.spacing.sm} 0 ${theme.spacing.lg}; diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx index cf9c3ec77ec..2a64221b39a 100644 --- a/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx +++ b/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx @@ -17,7 +17,6 @@ import { Unsubscribable } from 'rxjs'; import { DisplayMode, displayModes, PanelEditorTab } from './types'; import { PanelEditorTabs } from './PanelEditorTabs'; import { DashNavTimeControls } from '../DashNav/DashNavTimeControls'; -import { BackButton } from 'app/core/components/BackButton/BackButton'; import { LocationState } from 'app/types'; import { calculatePanelSize } from './utils'; import { initPanelEditor, panelEditorCleanUp, updatePanelEditorUIState } from './state/actions'; @@ -29,6 +28,7 @@ import { DashNavButton } from 'app/features/dashboard/components/DashNav/DashNav import { VariableModel } from 'app/features/templating/types'; import { getVariables } from 'app/features/variables/state/selectors'; import { SubMenuItems } from 'app/features/dashboard/components/SubMenu/SubMenuItems'; +import { BackButton } from 'app/core/components/BackButton/BackButton'; interface OwnProps { dashboard: DashboardModel; @@ -231,7 +231,7 @@ export class PanelEditorUnconnected extends PureComponent { return (
- + {dashboard.title} / Edit Panel
diff --git a/public/app/features/explore/RichHistory/RichHistoryCard.tsx b/public/app/features/explore/RichHistory/RichHistoryCard.tsx index 655f4a53b33..3fbcc622c2e 100644 --- a/public/app/features/explore/RichHistory/RichHistoryCard.tsx +++ b/public/app/features/explore/RichHistory/RichHistoryCard.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { connect } from 'react-redux'; import { hot } from 'react-hot-loader'; import { css, cx } from 'emotion'; -import { stylesFactory, useTheme, TextArea, Button, Icon } from '@grafana/ui'; +import { stylesFactory, useTheme, TextArea, Button, IconButton } from '@grafana/ui'; import { GrafanaTheme, AppEvents, DataSourceApi } from '@grafana/data'; import { RichHistoryQuery, ExploreId } from 'app/types/explore'; @@ -77,7 +77,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme, isRemoved: boolean) => { display: flex; justify-content: flex-end; font-size: ${theme.typography.size.base}; - svg { + button { margin-left: ${theme.spacing.sm}; } `, @@ -212,17 +212,17 @@ export function RichHistoryCard(props: Props) { const queryActionButtons = (
- 0 ? 'Edit comment' : 'Add comment'} /> - - {!isRemoved && } - - + {!isRemoved && } + + diff --git a/public/app/plugins/datasource/elasticsearch/configuration/DataLinks.tsx b/public/app/plugins/datasource/elasticsearch/configuration/DataLinks.tsx index 0702531a6ce..06d09451577 100644 --- a/public/app/plugins/datasource/elasticsearch/configuration/DataLinks.tsx +++ b/public/app/plugins/datasource/elasticsearch/configuration/DataLinks.tsx @@ -67,7 +67,7 @@ export const DataLinks = (props: Props) => { className={css` margin-right: 10px; `} - icon="plus-circle" + icon="plus" onClick={event => { event.preventDefault(); const newDataLinks = [...(value || []), { field: '', url: '' }]; diff --git a/public/app/plugins/panel/table/column_options.html b/public/app/plugins/panel/table/column_options.html index 51a355b1871..4bee4cc38b8 100644 --- a/public/app/plugins/panel/table/column_options.html +++ b/public/app/plugins/panel/table/column_options.html @@ -182,7 +182,7 @@
diff --git a/public/sass/_variables.dark.generated.scss b/public/sass/_variables.dark.generated.scss index eee9f1551a7..e56ce9c88f4 100644 --- a/public/sass/_variables.dark.generated.scss +++ b/public/sass/_variables.dark.generated.scss @@ -131,7 +131,7 @@ $panel-corner: $panel-bg; // page header $page-header-bg: #202226; $page-header-shadow: inset 0px -4px 14px $dark-3; -$page-header-border-color: $dark-9; +$page-header-border-color: #202226; $divider-border-color: $gray-1; diff --git a/public/sass/_variables.light.generated.scss b/public/sass/_variables.light.generated.scss index 3d2412b51a0..fc48ec0f999 100644 --- a/public/sass/_variables.light.generated.scss +++ b/public/sass/_variables.light.generated.scss @@ -121,9 +121,9 @@ $panel-header-hover-bg: $gray-6; $panel-corner: $gray-4; // Page header -$page-header-bg: linear-gradient(90deg, $white, #e9edf2); +$page-header-bg: #e9edf2; $page-header-shadow: inset 0px -3px 10px $gray-6; -$page-header-border-color: $gray-4; +$page-header-border-color: #c7d0d9; $divider-border-color: $gray-2; diff --git a/public/sass/components/_navbar.scss b/public/sass/components/_navbar.scss index cfc98338f3a..e5df8cd791c 100644 --- a/public/sass/components/_navbar.scss +++ b/public/sass/components/_navbar.scss @@ -184,7 +184,7 @@ i.navbar-page-btn__search { } &:hover { - .fa { + svg { color: $text-color; } }