From 7626ce9922ccac4b15f82853eef8439ab37d78a7 Mon Sep 17 00:00:00 2001 From: Dominik Prokop Date: Mon, 4 Feb 2019 17:28:57 +0100 Subject: [PATCH] WIP Enable js defined theme to be used in SASS --- package.json | 1 + packages/grafana-ui/src/index.ts | 1 + packages/grafana-ui/src/theme.d.ts | 116 ++++++++++++++++++++++ packages/grafana-ui/src/theme.js | 15 +++ packages/grafana-ui/src/themes/dark.js | 64 ++++++++++++ packages/grafana-ui/src/themes/default.js | 47 +++++++++ packages/grafana-ui/src/themes/light.js | 65 ++++++++++++ public/sass/_variables.dark.scss | 101 +++++++++---------- public/sass/_variables.light.scss | 94 +++++++++--------- public/sass/_variables.scss | 44 ++++---- scripts/webpack/getThemeVariable.js | 53 ++++++++++ scripts/webpack/sass.rule.js | 13 ++- scripts/webpack/webpack.hot.js | 10 +- yarn.lock | 5 + 14 files changed, 506 insertions(+), 123 deletions(-) create mode 100644 packages/grafana-ui/src/theme.d.ts create mode 100644 packages/grafana-ui/src/theme.js create mode 100644 packages/grafana-ui/src/themes/dark.js create mode 100644 packages/grafana-ui/src/themes/default.js create mode 100644 packages/grafana-ui/src/themes/light.js create mode 100644 scripts/webpack/getThemeVariable.js diff --git a/package.json b/package.json index 77fd92baf57..60a8a20cde3 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "ng-annotate-webpack-plugin": "^0.3.0", "ngtemplate-loader": "^2.0.1", "node-sass": "^4.11.0", + "node-sass-utils": "^1.1.2", "npm": "^5.4.2", "optimize-css-assets-webpack-plugin": "^4.0.2", "phantomjs-prebuilt": "^2.1.15", diff --git a/packages/grafana-ui/src/index.ts b/packages/grafana-ui/src/index.ts index 974d976bbef..4ddc7c8485a 100644 --- a/packages/grafana-ui/src/index.ts +++ b/packages/grafana-ui/src/index.ts @@ -1,3 +1,4 @@ export * from './components'; export * from './types'; export * from './utils'; +export * from './theme'; diff --git a/packages/grafana-ui/src/theme.d.ts b/packages/grafana-ui/src/theme.d.ts new file mode 100644 index 00000000000..015bcd16136 --- /dev/null +++ b/packages/grafana-ui/src/theme.d.ts @@ -0,0 +1,116 @@ +export interface GrafanaThemeType { + name: string; + // TODO: not sure if should be a part of theme + brakpoints: { + xs: string; + s: string; + m: string; + l: string; + xl: string; + }; + typography: { + fontFamily: { + sansSerif: string; + serif: string; + monospace: string; + }; + size: { + base: string; + xs: string; + s: string; + m: string; + l: string; + }; + weight: { + light: number; + normal: number; + semibold: number; + }; + lineHeight: { + xs: number; //1 + s: number; //1.1 + m: number; // 4/3 + l: number; // 1.5 + }; + // TODO: Refactor to use size instead of custom defs + heading: { + h1: string; + h2: string; + h3: string; + h4: string; + h5: string; + h6: string; + }; + }; + spacing: { + xs: string; + s: string; + m: string; + l: string; + gutter: string; + }; + border: { + radius: { + xs: string; + s: string; + m: string; + }; + }; + colors: { + black: string; + white: string; + dark1: string; + dark2: string; + dark3: string; + dark4: string; + dark5: string; + gray1: string; + gray2: string; + gray3: string; + gray4: string; + gray5: string; + gray6: string; + gray7: string; + grayBlue: string; + inputBlack: string; + + // Accent colors + blue: string; + blueLight: string; + blueDark: string; + green: string; + red: string; + yellow: string; + pink: string; + purple: string; + variable: string; + orange: string; + queryRed: string; + queryGreen: string; + queryPurple: string; + queryKeyword: string; + queryOrange: string; + + // Status colors + online: string; + warn: string; + critical: string; + + // TODO: should this be a part of theme? + bodyBg: string; + pageBg: string; + bodyColor: string; + textColor: string; + textColorStrong: string; + textColorWeak: string; + textColorFaint: string; + textColorEmphasis: string; + linkColor: string; + linkColorDisabled: string; + linkColorHover: string; + linkColorExternal: string; + headingColor: string; + }; +} +export function getTheme(): GrafanaThemeType +export function mockTheme(themeMock: Partial): () => void diff --git a/packages/grafana-ui/src/theme.js b/packages/grafana-ui/src/theme.js new file mode 100644 index 00000000000..3d0695e2490 --- /dev/null +++ b/packages/grafana-ui/src/theme.js @@ -0,0 +1,15 @@ +const darkTheme = require('./themes/dark'); +const lightTheme = require('./themes/light'); + +const getTheme = name => (name === 'light' ? lightTheme : darkTheme); + +const mockTheme = mock => { + const originalGetTheme = getTheme; + getTheme = () => mock; + return () => (getTheme = originalGetTheme); +}; + +module.exports = { + getTheme, + mockTheme, +}; diff --git a/packages/grafana-ui/src/themes/dark.js b/packages/grafana-ui/src/themes/dark.js new file mode 100644 index 00000000000..c80a4593f53 --- /dev/null +++ b/packages/grafana-ui/src/themes/dark.js @@ -0,0 +1,64 @@ + + +const defaultTheme = require('./default'); +const tinycolor = require('tinycolor2'); + +const basicColors = { + black: '#00ff00', + white: '#ffffff', + dark1: '#141414', + dark2: '#1f1f20', + dark3: '#262628', + dark4: '#333333', + dark5: '#444444', + gray1: '#555555', + gray2: '#8e8e8e', + gray3: '#b3b3b3', + gray4: '#d8d9da', + gray5: '#ececec', + gray6: '#f4f5f8', + gray7: '#fbfbfb', + grayBlue: '#212327', + blue: '#33b5e5', + blueDark: '#005f81', + blueLight: '#00a8e6', // not used in dark theme + green: '#299c46', + red: '#d44a3a', + yellow: '#ecbb13', + pink: '#ff4444', + purple: '#9933cc', + variable: '#32d1df', + orange: '#eb7b18', +}; + +const darkTheme = { + ...defaultTheme, + name: 'Grafana Dark', + colors: { + ...basicColors, + inputBlack: '#09090b', + queryRed: '#e24d42', + queryGreen: '#74e680', + queryPurple: '#fe85fc', + queryKeyword: '#66d9ef', + queryOrange: 'eb7b18', + online: '#10a345', + warn: '#f79520', + critical: '#ed2e18', + bodyBg: '#171819', + pageBg: '#161719', + bodyColor: basicColors.gray4, + textColor: basicColors.gray4, + textColorStrong: basicColors.white, + textColorWeak: basicColors.gray2, + textColorEmphasis: basicColors.gray5, + textColorFaint: basicColors.dark5, + linkColor: new tinycolor(basicColors.white).darken(11).toString(), + linkColorDisabled: new tinycolor(basicColors.white).darken(11).toString(), + linkColorHover: basicColors.white, + linkColorExternal: basicColors.blue, + headingColor: new tinycolor(basicColors.white).darken(11).toString(), + } +} + +module.exports = darkTheme; diff --git a/packages/grafana-ui/src/themes/default.js b/packages/grafana-ui/src/themes/default.js new file mode 100644 index 00000000000..59ed050e360 --- /dev/null +++ b/packages/grafana-ui/src/themes/default.js @@ -0,0 +1,47 @@ + + +const theme = { + name: 'Grafana Default', + typography: { + fontFamily: { + sansSerif: "'Roboto', Helvetica, Arial, sans-serif;", + serif: "Georgia, 'Times New Roman', Times, serif;", + monospace: "Menlo, Monaco, Consolas, 'Courier New', monospace;" + }, + size: { + base: '13px', + xs: '10px', + s: '12px', + m: '14px', + l: '18px', + }, + heading: { + h1: '2rem', + h2: '1.75rem', + h3: '1.5rem', + h4: '1.3rem', + h5: '1.2rem', + h6: '1rem', + }, + weight: { + light: 300, + normal: 400, + semibold: 500, + }, + lineHeight: { + xs: 1, + s: 1.1, + m: 4/3, + l: 1.5 + } + }, + brakpoints: { + xs: '0', + s: '544px', + m: '768px', + l: '992px', + xl: '1200px' + } +}; + +module.exports = theme; diff --git a/packages/grafana-ui/src/themes/light.js b/packages/grafana-ui/src/themes/light.js new file mode 100644 index 00000000000..84d1e656baa --- /dev/null +++ b/packages/grafana-ui/src/themes/light.js @@ -0,0 +1,65 @@ +// import { GrafanaThemeType } from "../theme"; + +const defaultTheme = require('./default'); +const tinycolor = require('tinycolor2'); + +const basicColors = { + black: '#000000', + white: '#ffffff', + dark1: '#13161d', + dark2: '#1e2028', + dark3: '#303133', + dark4: '#35373f', + dark5: '#41444b', + gray1: '#52545c', + gray2: '#767980', + gray3: '#acb6bf', + gray4: '#c7d0d9', + gray5: '#dde4ed', + gray6: '#e9edf2', + gray7: '#f7f8fa', + grayBlue: '#212327', // not used in light theme + blue: '#0083b3', + blueDark: '#005f81', + blueLight: '#00a8e6', + green: '#3aa655', + red: '#d44939', + yellow: '#ff851b', + pink: '#e671b8', + purple: '#9954bb', + variable: '#0083b3', + orange: '#ff7941', +}; + +const lightTheme/*: GrafanaThemeType*/ = { + ...defaultTheme, + name: 'Grafana Light', + colors: { + ...basicColors, + variable: basicColors.blue, + inputBlack: '#09090b', + queryRed: basicColors.red, + queryGreen: basicColors.green, + queryPurple: basicColors.purple, + queryKeyword: basicColors.blue, + queryOrange: basicColors.orange, + online: '#01a64f', + warn: '#f79520', + critical: '#ec2128', + bodyBg: basicColors.gray7, + pageBg: basicColors.gray7, + bodyColor: basicColors.gray1, + textColor: basicColors.gray1, + textColorStrong: basicColors.dark2, + textColorWeak: basicColors.gray2, + textColorEmphasis: basicColors.gray5, + textColorFaint: basicColors.dark4, + linkColor: basicColors.gray1, + linkColorDisabled: new tinycolor(basicColors.gray1).lighten(30).toString(), + linkColorHover: new tinycolor(basicColors.gray1).darken(20).toString(), + linkColorExternal: basicColors.blueLight, + headingColor: basicColors.gray1, + } +} + +module.exports = lightTheme; diff --git a/public/sass/_variables.dark.scss b/public/sass/_variables.dark.scss index 7b0ed869bdc..61e2c8bfc76 100644 --- a/public/sass/_variables.dark.scss +++ b/public/sass/_variables.dark.scss @@ -3,73 +3,69 @@ $theme-name: dark; -// Grays // ------------------------- -$black: #000; +$black: getThemeVariable('colors.black', $theme-name); +$dark-1: getThemeVariable('colors.dark1', $theme-name); +$dark-2: getThemeVariable('colors.dark2', $theme-name); +$dark-3: getThemeVariable('colors.dark3', $theme-name); +$dark-4: getThemeVariable('colors.dark4', $theme-name); +$dark-5: getThemeVariable('colors.dark5', $theme-name); +$gray-1: getThemeVariable('colors.gray1', $theme-name); +$gray-2: getThemeVariable('colors.gray2', $theme-name); +$gray-3: getThemeVariable('colors.gray3', $theme-name); +$gray-4: getThemeVariable('colors.gray4', $theme-name); +$gray-5: getThemeVariable('colors.gray5', $theme-name); +$gray-6: getThemeVariable('colors.gray6', $theme-name); +$gray-7: getThemeVariable('colors.gray7', $theme-name); -// ------------------------- -$black: #000; -$dark-1: #141414; -$dark-2: #1f1f20; -$dark-3: #262628; -$dark-4: #333333; -$dark-5: #444444; -$gray-1: #555555; -$gray-2: #8e8e8e; -$gray-3: #b3b3b3; -$gray-4: #d8d9da; -$gray-5: #ececec; -$gray-6: #f4f5f8; -$gray-7: #fbfbfb; +$gray-blue: getThemeVariable('colors.grayBlue', $theme-name); +$input-black: getThemeVariable('colors.inputBlack', $theme-name); -$gray-blue: #212327; -$input-black: #09090b; - -$white: #fff; +$white: getThemeVariable('colors.white', $theme-name); // Accent colors // ------------------------- -$blue: #33b5e5; -$blue-dark: #005f81; -$green: #299c46; -$red: #d44a3a; -$yellow: #ecbb13; -$pink: #ff4444; -$purple: #9933cc; -$variable: #32d1df; -$orange: #eb7b18; +$blue: getThemeVariable('colors.blue', $theme-name); +$blue-dark: getThemeVariable('colors.blueDark', $theme-name); +$green: getThemeVariable('colors.green', $theme-name); +$red: getThemeVariable('colors.red', $theme-name); +$yellow: getThemeVariable('colors.yellow', $theme-name); +$pink: getThemeVariable('colors.pink', $theme-name); +$purple: getThemeVariable('colors.purple', $theme-name); +$variable: getThemeVariable('colors.variable', $theme-name); +$orange: getThemeVariable('colors.orange', $theme-name); $brand-primary: $orange; $brand-success: $green; $brand-warning: $brand-primary; $brand-danger: $red; -$query-red: #e24d42; -$query-green: #74e680; -$query-purple: #fe85fc; -$query-keyword: #66d9ef; -$query-orange: $orange; +$query-red: getThemeVariable('colors.queryRed', $theme-name); +$query-green: getThemeVariable('colors.queryGreen', $theme-name); +$query-purple: getThemeVariable('colors.queryPurple', $theme-name); +$query-keyword: getThemeVariable('colors.queryKeyword', $theme-name); +$query-orange: getThemeVariable('colors.queryOrange', $theme-name); // Status colors // ------------------------- -$online: #10a345; -$warn: #f79520; -$critical: #ed2e18; +$online: getThemeVariable('colors.online', $theme-name); +$warn: getThemeVariable('colors.warn', $theme-name); +$critical: getThemeVariable('colors.critical', $theme-name); // Scaffolding // ------------------------- -$body-bg: rgb(23, 24, 25); -$page-bg: rgb(22, 23, 25); +$body-bg: getThemeVariable('colors.bodyBg', $theme-name); +$page-bg: getThemeVariable('colors.pageBg', $theme-name); -$body-color: $gray-4; -$text-color: $gray-4; -$text-color-strong: $white; -$text-color-weak: $gray-2; -$text-color-faint: $dark-5; -$text-color-emphasis: $gray-5; +$body-color: getThemeVariable('colors.bodyColor', $theme-name); +$text-color: getThemeVariable('colors.textColor', $theme-name); +$text-color-strong: getThemeVariable('colors.textColorStrong', $theme-name); +$text-color-weak: getThemeVariable('colors.textColorWeak', $theme-name); +$text-color-faint: getThemeVariable('colors.textColorFaint', $theme-name); +$text-color-emphasis: getThemeVariable('colors.textColorEmphasis', $theme-name); -$text-shadow-strong: 1px 1px 4px $black; -$text-shadow-faint: 1px 1px 4px rgb(45, 45, 45); +$text-shadow-strong: 1px 1px 4px getThemeVariable('colors.black', $theme-name); +$text-shadow-faint: 1px 1px 4px #2d2d2d; // gradients $brand-gradient: linear-gradient( @@ -84,10 +80,11 @@ $edit-gradient: linear-gradient(180deg, rgb(22, 23, 25) 50%, #090909); // Links // ------------------------- -$link-color: darken($white, 11%); -$link-color-disabled: darken($link-color, 30%); -$link-hover-color: $white; -$external-link-color: $blue; +$link-color: getThemeVariable('colors.linkColor', $theme-name); +$link-color-disabled: getThemeVariable('colors.linkColorDisabled', $theme-name); +$link-hover-color: getThemeVariable('colors.linkColorHover', $theme-name); + +$external-link-color: getThemeVariable('colors.linkColorExternal', $theme-name); // Typography // ------------------------- @@ -135,7 +132,7 @@ $list-item-shadow: $card-shadow; $empty-list-cta-bg: $gray-blue; // Scrollbars -$scrollbarBackground: #404357; +$scrollbarBackground: #aeb5df; $scrollbarBackground2: #3a3a3a; $scrollbarBorder: black; diff --git a/public/sass/_variables.light.scss b/public/sass/_variables.light.scss index 10c074e1481..ad2b22e201a 100644 --- a/public/sass/_variables.light.scss +++ b/public/sass/_variables.light.scss @@ -12,83 +12,85 @@ $theme-name: light; $black: #000; // ------------------------- -$black: #000; -$dark-1: #13161d; -$dark-2: #1e2028; -$dark-3: #303133; -$dark-4: #35373f; -$dark-5: #41444b; -$gray-1: #52545c; -$gray-2: #767980; -$gray-3: #acb6bf; -$gray-4: #c7d0d9; -$gray-5: #dde4ed; -$gray-6: #e9edf2; -$gray-7: #f7f8fa; +$black: getThemeVariable('colors.black', $theme-name); +$dark-1: getThemeVariable('colors.dark1', $theme-name); +$dark-2: getThemeVariable('colors.dark2', $theme-name); +$dark-3: getThemeVariable('colors.dark3', $theme-name); +$dark-4: getThemeVariable('colors.dark4', $theme-name); +$dark-5: getThemeVariable('colors.dark5', $theme-name); +$gray-1: getThemeVariable('colors.gray1', $theme-name); +$gray-2: getThemeVariable('colors.gray2', $theme-name); +$gray-3: getThemeVariable('colors.gray3', $theme-name); +$gray-4: getThemeVariable('colors.gray4', $theme-name); +$gray-5: getThemeVariable('colors.gray5', $theme-name); +$gray-6: getThemeVariable('colors.gray6', $theme-name); +$gray-7: getThemeVariable('colors.gray7', $theme-name); -$white: #fff; +$white: getThemeVariable('colors.white', $theme-name); // Accent colors // ------------------------- -$blue: #0083b3; -$blue-dark: #005f81; -$blue-light: #00a8e6; -$green: #3aa655; -$red: #d44939; -$yellow: #ff851b; -$orange: #ff7941; -$pink: #e671b8; -$purple: #9954bb; -$variable: $blue; +$blue: getThemeVariable('colors.blue', $theme-name); +$blue-dark: getThemeVariable('colors.blueDark', $theme-name); +$blue-light: getThemeVariable('colors.blueLight', $theme-name); +$green: getThemeVariable('colors.green', $theme-name); +$red: getThemeVariable('colors.red', $theme-name); +$yellow: getThemeVariable('colors.yellow', $theme-name); +$orange: getThemeVariable('colors.orange', $theme-name); +$pink: getThemeVariable('colors.pink', $theme-name); +$purple: getThemeVariable('colors.purple', $theme-name); +$variable: getThemeVariable('colors.variable', $theme-name); $brand-primary: $orange; $brand-success: $green; $brand-warning: $orange; $brand-danger: $red; -$query-red: $red; -$query-green: $green; -$query-purple: $purple; -$query-orange: $orange; -$query-keyword: $blue; +$query-red: getThemeVariable('colors.queryRed', $theme-name); +$query-green: getThemeVariable('colors.queryGreen', $theme-name); +$query-purple: getThemeVariable('colors.queryPurple', $theme-name); +$query-keyword: getThemeVariable('colors.queryKeyword', $theme-name); +$query-orange: getThemeVariable('colors.queryOrange', $theme-name); // Status colors // ------------------------- -$online: #01a64f; -$warn: #f79520; -$critical: #ec2128; +$online: getThemeVariable('colors.online', $theme-name); +$warn: getThemeVariable('colors.warn', $theme-name); +$critical: getThemeVariable('colors.critical', $theme-name); // Scaffolding // ------------------------- -$body-bg: $gray-7; -$page-bg: $gray-7; -$body-color: $gray-1; -$text-color: $gray-1; -$text-color-strong: $dark-2; -$text-color-weak: $gray-2; -$text-color-faint: $gray-4; -$text-color-emphasis: $dark-5; +$body-bg: getThemeVariable('colors.bodyBg', $theme-name); +$page-bg: getThemeVariable('colors.pageBg', $theme-name); + +$body-color: getThemeVariable('colors.bodyColor', $theme-name); +$text-color: getThemeVariable('colors.textColor', $theme-name); +$text-color-strong: getThemeVariable('colors.textColorStrong', $theme-name); +$text-color-weak: getThemeVariable('colors.textColorWeak', $theme-name); +$text-color-faint: getThemeVariable('colors.textColorFaint', $theme-name); +$text-color-emphasis: getThemeVariable('colors.textColorEmphasis', $theme-name); $text-shadow-strong: none; $text-shadow-faint: none; $textShadow: none; // gradients -$brand-gradient: linear-gradient(to right, rgba(255, 213, 0, 1) 0%, rgba(255, 68, 0, 1) 99%, rgba(255, 68, 0, 1) 100%); +$brand-gradient: linear-gradient(to right, hsl(50, 100%, 50%) 0%, rgba(255, 68, 0, 1) 99%, rgba(255, 68, 0, 1) 100%); $page-gradient: linear-gradient(180deg, $white 10px, $gray-7 100px); $edit-gradient: linear-gradient(-60deg, $gray-7, #f5f6f9 70%, $gray-7 98%); // Links // ------------------------- -$link-color: $gray-1; -$link-color-disabled: lighten($link-color, 30%); -$link-hover-color: darken($link-color, 20%); -$external-link-color: $blue-light; +$link-color: getThemeVariable('colors.linkColor', $theme-name); +$link-color-disabled: getThemeVariable('colors.linkColorDisabled', $theme-name); +$link-hover-color: getThemeVariable('colors.linkColorHover', $theme-name); + +$external-link-color: getThemeVariable('colors.linkColorExternal', $theme-name); // Typography // ------------------------- -$headings-color: $text-color; +$headings-color: getThemeVariable('colors.headingColor', $theme-name); $abbr-border-color: $gray-2 !default; $text-muted: $text-color-weak; diff --git a/public/sass/_variables.scss b/public/sass/_variables.scss index 4e9e69c4d2f..eab0e8c7f5a 100644 --- a/public/sass/_variables.scss +++ b/public/sass/_variables.scss @@ -47,45 +47,45 @@ $enable-flex: true; // Typography // ------------------------- -$font-family-sans-serif: 'Roboto', Helvetica, Arial, sans-serif; -$font-family-serif: Georgia, 'Times New Roman', Times, serif; -$font-family-monospace: Menlo, Monaco, Consolas, 'Courier New', monospace; +$font-family-sans-serif: getThemeVariable('typography.fontFamily.sansSerif'); +$font-family-serif: getThemeVariable('typography.fontFamily.serif'); +$font-family-monospace: getThemeVariable('typography.fontFamily.monospace'); $font-family-base: $font-family-sans-serif !default; -$font-size-root: 14px !default; -$font-size-base: 13px !default; +$font-size-root: getThemeVariable('typography.size.m') !default; +$font-size-base: getThemeVariable('typography.size.base') !default; -$font-size-lg: 18px !default; -$font-size-md: 14px !default; -$font-size-sm: 12px !default; -$font-size-xs: 10px !default; +$font-size-lg: getThemeVariable('typography.size.l') !default; +$font-size-md: getThemeVariable('typography.size.m') !default; +$font-size-sm: getThemeVariable('typography.size.s') !default; +$font-size-xs: getThemeVariable('typography.size.xs') !default; -$line-height-base: 1.5 !default; -$font-weight-semi-bold: 500; +$line-height-base: getThemeVariable('typography.lineHeight.l') !default; +$font-weight-semi-bold: getThemeVariable('typography.weight.semibold'); -$font-size-h1: 2rem !default; -$font-size-h2: 1.75rem !default; -$font-size-h3: 1.5rem !default; -$font-size-h4: 1.3rem !default; -$font-size-h5: 1.2rem !default; -$font-size-h6: 1rem !default; +$font-size-h1: getThemeVariable('typography.heading.h1') !default; +$font-size-h2: getThemeVariable('typography.heading.h2') !default; +$font-size-h3: getThemeVariable('typography.heading.h3') !default; +$font-size-h4: getThemeVariable('typography.heading.h4') !default; +$font-size-h5: getThemeVariable('typography.heading.h5') !default; +$font-size-h6: getThemeVariable('typography.heading.h6') !default; $display1-size: 6rem !default; $display2-size: 5.5rem !default; $display3-size: 4.5rem !default; $display4-size: 3.5rem !default; -$display1-weight: 400 !default; -$display2-weight: 400 !default; -$display3-weight: 400 !default; -$display4-weight: 400 !default; +$display1-weight: getThemeVariable('typography.weight.normal') !default; +$display2-weight: getThemeVariable('typography.weight.normal') !default; +$display3-weight: getThemeVariable('typography.weight.normal') !default; +$display4-weight: getThe1meVariable('typography.weight.normal') !default; $lead-font-size: 1.25rem !default; $lead-font-weight: 300 !default; $headings-margin-bottom: ($spacer / 2) !default; $headings-font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif; -$headings-font-weight: 400 !default; +$headings-font-weight: getThemeVariable('typography.weight.normal') !default; $headings-line-height: 1.1 !default; $hr-border-width: $border-width !default; diff --git a/scripts/webpack/getThemeVariable.js b/scripts/webpack/getThemeVariable.js new file mode 100644 index 00000000000..c0b6bc4ed79 --- /dev/null +++ b/scripts/webpack/getThemeVariable.js @@ -0,0 +1,53 @@ +const sass = require('node-sass'); +const sassUtils = require('node-sass-utils')(sass); +const { getTheme } = require('../../packages/grafana-ui/src/theme'); +const { get } = require('lodash'); +const tinycolor = require('tinycolor2'); + +const units = ['rem', 'em', 'vh', 'vw', 'vmin', 'vmax', 'ex', '%', 'px', 'cm', 'mm', 'in', 'pt', 'pc', 'ch']; +const matchDimension = value => value.match(/[a-zA-Z]+|[0-9]+/g); + +const isHex = value => { + const hexRegex = /^((0x){0,1}|#{0,1})([0-9A-F]{8}|[0-9A-F]{6})$/gi; + return hexRegex.test(value); +}; + +const isDimension = value => { + if( typeof value !== "string") { + return false; + } + + const [val, unit] = matchDimension(value); + return units.indexOf(unit) > -1 +}; + +/** + * @param {SassString} variablePath + * @param {"dark"|"light"} themeName + */ +function getThemeVariable(variablePath, themeName) { + const theme = getTheme(themeName.getValue()); + const variable = get(theme, variablePath.getValue()); + + if (!variable) { + throw new Error(`${variablePath} is not defined fo ${themeName}`); + } + + if (isHex(variable)) { + const rgb = new tinycolor(variable).toRgb(); + const color = sass.types.Color(rgb.r, rgb.g, rgb.b); + return color; + } + + if (isDimension(variable)) { + const [value, unit] = matchDimension(variable) + + const tmp = new sassUtils.SassDimension(parseInt(value,10), unit); + // debugger + return sassUtils.castToSass(tmp) + } + + return sassUtils.castToSass(variable); +} + +module.exports = getThemeVariable; diff --git a/scripts/webpack/sass.rule.js b/scripts/webpack/sass.rule.js index 75455fc4184..78f6b60d33f 100644 --- a/scripts/webpack/sass.rule.js +++ b/scripts/webpack/sass.rule.js @@ -1,6 +1,7 @@ 'use strict'; -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const getThemeVariable = require('./getThemeVariable'); module.exports = function(options) { return { @@ -23,7 +24,15 @@ module.exports = function(options) { config: { path: __dirname + '/postcss.config.js' }, }, }, - { loader: 'sass-loader', options: { sourceMap: options.sourceMap } }, + { + loader: 'sass-loader', + options: { + sourceMap: options.sourceMap, + functions: { + 'getThemeVariable($themeVar, $themeName: dark)': getThemeVariable, + }, + }, + }, ], }; }; diff --git a/scripts/webpack/webpack.hot.js b/scripts/webpack/webpack.hot.js index b37e4c08592..4519e292c6b 100644 --- a/scripts/webpack/webpack.hot.js +++ b/scripts/webpack/webpack.hot.js @@ -8,6 +8,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin'); const CleanWebpackPlugin = require('clean-webpack-plugin'); const IgnoreNotFoundExportPlugin = require("./IgnoreNotFoundExportPlugin.js"); +const getThemeVariable = require("./getThemeVariable"); module.exports = merge(common, { entry: { @@ -85,7 +86,14 @@ module.exports = merge(common, { config: { path: __dirname + '/postcss.config.js' }, }, }, - 'sass-loader', // compiles Sass to CSS + { + loader: 'sass-loader', + options: { + functions: { + "getThemeVariable($themeVar, $themeName: dark)": getThemeVariable + } + } + } ], }, { diff --git a/yarn.lock b/yarn.lock index 169abd40ee4..bc94a05d702 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11910,6 +11910,11 @@ node-releases@^1.0.0-alpha.11, node-releases@^1.1.3: dependencies: semver "^5.3.0" +node-sass-utils@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/node-sass-utils/-/node-sass-utils-1.1.2.tgz#d03639cfa4fc962398ba3648ab466f0db7cc2131" + integrity sha1-0DY5z6T8liOYujZIq0ZvDbfMITE= + node-sass@^4.11.0: version "4.11.0" resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.11.0.tgz#183faec398e9cbe93ba43362e2768ca988a6369a"