From 80ad75503b7ab5e847bb79bbe967c6e4331f8439 Mon Sep 17 00:00:00 2001
From: tristanliu <37809633+sevenliu1896@users.noreply.github.com>
Date: Mon, 20 Nov 2023 12:04:08 +0800
Subject: [PATCH] [improvement][semantic-fe] Upgrading antd version to 5.x,
extracting the batch operation button component, optimizing the interaction
for system settings, and expanding the configuration generation types for
list-to-select component. (#404)
* [improvement][semantic-fe] Add model alias setting & Add view permission restrictions to the model permission management tab.
[improvement][semantic-fe] Add permission control to the action buttons for the main domain; apply high sensitivity filtering to the authorization of metrics/dimensions.
[improvement][semantic-fe] Optimize the editing mode in the dimension/metric/datasource components to use the modelId stored in the database for data, instead of relying on the data from the state manager.
* [improvement][semantic-fe] Add time granularity setting in the data source configuration.
* [improvement][semantic-fe] Dictionary import for dimension values supported in Q&A visibility
* [improvement][semantic-fe] Modification of data source creation prompt wording"
* [improvement][semantic-fe] metric market experience optimization
* [improvement][semantic-fe] enhance the analysis of metric trends
* [improvement][semantic-fe] optimize the presentation of metric trend permissions
* [improvement][semantic-fe] add metric trend download functionality
* [improvement][semantic-fe] fix the dimension initialization issue in metric correlation
* [improvement][semantic-fe] Fix the issue of database changes not taking effect when creating based on an SQL data source.
* [improvement][semantic-fe] Optimizing pagination logic and some CSS styles
* [improvement][semantic-fe] Fixing the API for the indicator list by changing "current" to "pageNum"
* [improvement][semantic-fe] Fixing the default value setting for the indicator list
* [improvement][semantic-fe] Adding batch operations for indicators/dimensions/models
* [improvement][semantic-fe] Replacing the single status update API for indicators/dimensions with a batch update API
* [improvement][semantic-fe] Redesigning the indicator homepage to incorporate trend charts and table functionality for indicators
* [improvement][semantic-fe] Optimizing the logic for setting dimension values and editing data sources, and adding system settings functionality
* [improvement][semantic-fe] Upgrading antd version to 5.x, extracting the batch operation button component, optimizing the interaction for system settings, and expanding the configuration generation types for list-to-select component.
---
.../packages/supersonic-fe/config/config.ts | 3 +
.../supersonic-fe/config/defaultSettings.ts | 4 +-
webapp/packages/supersonic-fe/package.json | 16 +-
webapp/packages/supersonic-fe/src/app.tsx | 2 +-
.../src/assets/css/variable.less | 2 +-
.../src/assets/style/color/bezierEasing.less | 110 ++
.../src/assets/style/color/colorPalette.less | 85 ++
.../src/assets/style/color/colors.less | 162 +++
.../src/assets/style/color/tinyColor.less | 1184 ++++++++++++++++
.../src/assets/style/compact.less | 4 +
.../src/assets/style/core/base.less | 10 +
.../src/assets/style/core/global.less | 491 +++++++
.../src/assets/style/core/iconfont.less | 22 +
.../src/assets/style/core/index.less | 5 +
.../src/assets/style/core/motion.less | 22 +
.../src/assets/style/core/motion/fade.less | 34 +
.../src/assets/style/core/motion/move.less | 129 ++
.../src/assets/style/core/motion/other.less | 51 +
.../src/assets/style/core/motion/slide.less | 131 ++
.../src/assets/style/core/motion/zoom.less | 179 +++
.../supersonic-fe/src/assets/style/css.js | 1 +
.../supersonic-fe/src/assets/style/dark.less | 4 +
.../src/assets/style/default.css | 1248 +++++++++++++++++
.../src/assets/style/default.less | 4 +
.../src/assets/style/index-pure.less | 2 +
.../supersonic-fe/src/assets/style/index.css | 1248 +++++++++++++++++
.../supersonic-fe/src/assets/style/index.d.ts | 1 +
.../supersonic-fe/src/assets/style/index.js | 1 +
.../supersonic-fe/src/assets/style/index.less | 3 +
.../src/assets/style/mixins/box.less | 7 +
.../src/assets/style/mixins/clearfix.less | 16 +
.../style/mixins/compact-item-vertical.less | 41 +
.../src/assets/style/mixins/compact-item.less | 133 ++
.../assets/style/mixins/compatibility.less | 13 +
.../src/assets/style/mixins/customize.less | 181 +++
.../src/assets/style/mixins/iconfont.less | 29 +
.../src/assets/style/mixins/index.less | 16 +
.../src/assets/style/mixins/modal-mask.less | 30 +
.../src/assets/style/mixins/motion.less | 33 +
.../assets/style/mixins/operation-unit.less | 15 +
.../src/assets/style/mixins/reset.less | 11 +
.../assets/style/mixins/rounded-arrow.less | 44 +
.../src/assets/style/mixins/size.less | 10 +
.../src/assets/style/mixins/typography.less | 58 +
.../src/assets/style/themes/compact.less | 295 ++++
.../src/assets/style/themes/dark.less | 457 ++++++
.../src/assets/style/themes/default.less | 1084 ++++++++++++++
.../src/assets/style/themes/index.less | 7 +
.../src/assets/style/themes/variable.less | 1139 +++++++++++++++
.../src/assets/style/variable.less | 4 +
.../BatchCtrlDropDownButton/index.less | 0
.../BatchCtrlDropDownButton/index.tsx | 165 +++
.../src/components/HeaderDropdown/index.less | 9 +-
.../src/components/MStar/index.tsx | 30 +
.../src/components/MStar/style.less | 6 +
.../RightContent/AvatarDropdown.tsx | 2 +-
.../src/components/RightContent/index.less | 54 +-
.../src/components/RightContent/index.tsx | 12 +-
.../src/components/StandardFormRow/index.less | 7 +-
.../src/components/TagSelect/index.less | 3 +-
webapp/packages/supersonic-fe/src/global.less | 156 +--
.../components/DataSourceBasicForm.tsx | 10 +-
.../components/DataSourceCreateForm.tsx | 49 +-
.../components/DataSourceFieldForm.tsx | 18 +-
.../src/pages/SemanticModel/Metric/Detail.tsx | 163 +--
.../src/pages/SemanticModel/Metric/Market.tsx | 174 +--
.../Metric/components/MetricStar.tsx | 38 +
.../src/pages/SemanticModel/Metric/style.less | 3 +-
.../pages/SemanticModel/OverviewContainer.tsx | 4 +-
.../components/ClassDataSourceTypeModal.tsx | 7 +-
.../components/ClassDimensionTable.tsx | 15 +-
.../components/ClassMetricTable.tsx | 88 +-
.../SemanticModel/components/DomainList.tsx | 61 +-
.../components/DomainManagerTab.tsx | 75 +-
.../components/MetricInfoCreateForm.tsx | 2 +-
.../components/ModelCreateFormModal.tsx | 2 +-
.../components/Permission/PermissionTable.tsx | 18 -
.../components/ProjectInfoForm.tsx | 2 +-
.../pages/SemanticModel/components/style.less | 41 +-
.../src/pages/SemanticModel/constant.ts | 6 +-
.../src/pages/SemanticModel/data.d.ts | 1 +
.../src/pages/SemanticModel/service.ts | 14 +
.../supersonic-fe/src/pages/System/index.tsx | 192 ++-
.../supersonic-fe/src/pages/System/types.ts | 1 +
84 files changed, 9472 insertions(+), 737 deletions(-)
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/color/bezierEasing.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/color/colorPalette.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/color/colors.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/color/tinyColor.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/compact.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/core/base.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/core/global.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/core/iconfont.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/core/index.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/core/motion.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/core/motion/fade.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/core/motion/move.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/core/motion/other.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/core/motion/slide.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/core/motion/zoom.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/css.js
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/dark.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/default.css
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/default.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/index-pure.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/index.css
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/index.d.ts
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/index.js
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/index.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/box.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/clearfix.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/compact-item-vertical.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/compact-item.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/compatibility.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/customize.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/iconfont.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/index.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/modal-mask.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/motion.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/operation-unit.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/reset.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/rounded-arrow.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/size.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/mixins/typography.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/themes/compact.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/themes/dark.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/themes/default.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/themes/index.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/themes/variable.less
create mode 100644 webapp/packages/supersonic-fe/src/assets/style/variable.less
create mode 100644 webapp/packages/supersonic-fe/src/components/BatchCtrlDropDownButton/index.less
create mode 100644 webapp/packages/supersonic-fe/src/components/BatchCtrlDropDownButton/index.tsx
create mode 100644 webapp/packages/supersonic-fe/src/components/MStar/index.tsx
create mode 100644 webapp/packages/supersonic-fe/src/components/MStar/style.less
create mode 100644 webapp/packages/supersonic-fe/src/pages/SemanticModel/Metric/components/MetricStar.tsx
diff --git a/webapp/packages/supersonic-fe/config/config.ts b/webapp/packages/supersonic-fe/config/config.ts
index f00cc80c2..fa65717b8 100644
--- a/webapp/packages/supersonic-fe/config/config.ts
+++ b/webapp/packages/supersonic-fe/config/config.ts
@@ -61,6 +61,9 @@ export default defineConfig({
theme: {
...themeSettings,
},
+ alias: {
+ 'antd/es/style': '@/assets/style',
+ },
esbuild: {},
title: false,
ignoreMomentLocale: true,
diff --git a/webapp/packages/supersonic-fe/config/defaultSettings.ts b/webapp/packages/supersonic-fe/config/defaultSettings.ts
index af5adf464..e3312defc 100644
--- a/webapp/packages/supersonic-fe/config/defaultSettings.ts
+++ b/webapp/packages/supersonic-fe/config/defaultSettings.ts
@@ -4,8 +4,8 @@ const Settings: LayoutSettings & {
pwa?: boolean;
logo?: string;
} = {
- navTheme: 'dark',
- primaryColor: '#296DF3',
+ navTheme: 'light',
+ colorPrimary: '#296DF3',
layout: 'top',
contentWidth: 'Fluid',
fixedHeader: false,
diff --git a/webapp/packages/supersonic-fe/package.json b/webapp/packages/supersonic-fe/package.json
index 7c28a2010..8fb8ce07d 100644
--- a/webapp/packages/supersonic-fe/package.json
+++ b/webapp/packages/supersonic-fe/package.json
@@ -52,15 +52,11 @@
"not ie <= 10"
],
"dependencies": {
- "@ant-design/charts": "^1.3.3",
- "@ant-design/cssinjs": "^1.10.1",
- "@ant-design/icons": "^4.7.0",
- "@ant-design/pro-card": "^1.11.13",
- "@ant-design/pro-components": "^2.4.4",
- "@ant-design/pro-descriptions": "^1.0.19",
- "@ant-design/pro-form": "^1.23.0",
- "@ant-design/pro-layout": "^6.38.22",
- "@ant-design/pro-table": "^2.80.6",
+ "@ant-design/icons": "^5.2.6",
+ "@ant-design/pro-card": "^2.5.26",
+ "@ant-design/pro-components": "^2.6.41",
+ "@ant-design/pro-layout": "^7.17.15",
+ "@ant-design/pro-table": "^3.13.9",
"@antv/dom-util": "^2.0.4",
"@antv/g6": "^4.8.14",
"@antv/g6-core": "^0.8.23",
@@ -73,7 +69,7 @@
"@umijs/route-utils": "^1.0.33",
"ace-builds": "^1.4.12",
"ahooks": "^3.7.7",
- "antd": "^4.24.8",
+ "antd": "^5.11.0",
"classnames": "^2.2.6",
"copy-to-clipboard": "^3.3.1",
"cross-env": "^7.0.3",
diff --git a/webapp/packages/supersonic-fe/src/app.tsx b/webapp/packages/supersonic-fe/src/app.tsx
index 76775a606..f0f7ca930 100644
--- a/webapp/packages/supersonic-fe/src/app.tsx
+++ b/webapp/packages/supersonic-fe/src/app.tsx
@@ -133,7 +133,7 @@ export const layout: RunTimeLayoutConfig = (params) => {
>
{dom}
{history.location.pathname !== '/chat' && !isMobile && (
-
+
)}
);
diff --git a/webapp/packages/supersonic-fe/src/assets/css/variable.less b/webapp/packages/supersonic-fe/src/assets/css/variable.less
index 0297bb9d2..9a2aad3e6 100644
--- a/webapp/packages/supersonic-fe/src/assets/css/variable.less
+++ b/webapp/packages/supersonic-fe/src/assets/css/variable.less
@@ -1,4 +1,4 @@
-@import '~antd/lib/style/themes/default';
+
// main
@primary: #225ace;
diff --git a/webapp/packages/supersonic-fe/src/assets/style/color/bezierEasing.less b/webapp/packages/supersonic-fe/src/assets/style/color/bezierEasing.less
new file mode 100644
index 000000000..f53ffb368
--- /dev/null
+++ b/webapp/packages/supersonic-fe/src/assets/style/color/bezierEasing.less
@@ -0,0 +1,110 @@
+/* stylelint-disable */
+.bezierEasingMixin() {
+@functions: ~`(function() {
+ var NEWTON_ITERATIONS = 4;
+ var NEWTON_MIN_SLOPE = 0.001;
+ var SUBDIVISION_PRECISION = 0.0000001;
+ var SUBDIVISION_MAX_ITERATIONS = 10;
+
+ var kSplineTableSize = 11;
+ var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
+
+ var float32ArraySupported = typeof Float32Array === 'function';
+
+ function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
+ function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
+ function C (aA1) { return 3.0 * aA1; }
+
+ // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
+ function calcBezier (aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; }
+
+ // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
+ function getSlope (aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); }
+
+ function binarySubdivide (aX, aA, aB, mX1, mX2) {
+ var currentX, currentT, i = 0;
+ do {
+ currentT = aA + (aB - aA) / 2.0;
+ currentX = calcBezier(currentT, mX1, mX2) - aX;
+ if (currentX > 0.0) {
+ aB = currentT;
+ } else {
+ aA = currentT;
+ }
+ } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
+ return currentT;
+ }
+
+ function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) {
+ for (var i = 0; i < NEWTON_ITERATIONS; ++i) {
+ var currentSlope = getSlope(aGuessT, mX1, mX2);
+ if (currentSlope === 0.0) {
+ return aGuessT;
+ }
+ var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
+ aGuessT -= currentX / currentSlope;
+ }
+ return aGuessT;
+ }
+
+ var BezierEasing = function (mX1, mY1, mX2, mY2) {
+ if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
+ throw new Error('bezier x values must be in [0, 1] range');
+ }
+
+ // Precompute samples table
+ var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
+ if (mX1 !== mY1 || mX2 !== mY2) {
+ for (var i = 0; i < kSplineTableSize; ++i) {
+ sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
+ }
+ }
+
+ function getTForX (aX) {
+ var intervalStart = 0.0;
+ var currentSample = 1;
+ var lastSample = kSplineTableSize - 1;
+
+ for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
+ intervalStart += kSampleStepSize;
+ }
+ --currentSample;
+
+ // Interpolate to provide an initial guess for t
+ var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);
+ var guessForT = intervalStart + dist * kSampleStepSize;
+
+ var initialSlope = getSlope(guessForT, mX1, mX2);
+ if (initialSlope >= NEWTON_MIN_SLOPE) {
+ return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
+ } else if (initialSlope === 0.0) {
+ return guessForT;
+ } else {
+ return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
+ }
+ }
+
+ return function BezierEasing (x) {
+ if (mX1 === mY1 && mX2 === mY2) {
+ return x; // linear
+ }
+ // Because JavaScript number are imprecise, we should guarantee the extremes are right.
+ if (x === 0) {
+ return 0;
+ }
+ if (x === 1) {
+ return 1;
+ }
+ return calcBezier(getTForX(x), mY1, mY2);
+ };
+ };
+
+ this.colorEasing = BezierEasing(0.26, 0.09, 0.37, 0.18);
+ // less 3 requires a return
+ return '';
+})()`;
+}
+// It is hacky way to make this function will be compiled preferentially by less
+// resolve error: `ReferenceError: colorPalette is not defined`
+// https://github.com/ant-design/ant-motion/issues/44
+.bezierEasingMixin();
diff --git a/webapp/packages/supersonic-fe/src/assets/style/color/colorPalette.less b/webapp/packages/supersonic-fe/src/assets/style/color/colorPalette.less
new file mode 100644
index 000000000..e662c072a
--- /dev/null
+++ b/webapp/packages/supersonic-fe/src/assets/style/color/colorPalette.less
@@ -0,0 +1,85 @@
+/* stylelint-disable no-duplicate-selectors */
+@import "bezierEasing";
+@import "tinyColor";
+
+// We create a very complex algorithm which take the place of original tint/shade color system
+// to make sure no one can understand it 👻
+// and create an entire color palette magicly by inputing just a single primary color.
+// We are using bezier-curve easing function and some color manipulations like tint/shade/darken/spin
+.colorPaletteMixin() {
+@functions: ~`(function() {
+ var hueStep = 2;
+ var saturationStep = 0.16;
+ var saturationStep2 = 0.05;
+ var brightnessStep1 = 0.05;
+ var brightnessStep2 = 0.15;
+ var lightColorCount = 5;
+ var darkColorCount = 4;
+
+ var getHue = function(hsv, i, isLight) {
+ var hue;
+ if (hsv.h >= 60 && hsv.h <= 240) {
+ hue = isLight ? hsv.h - hueStep * i : hsv.h + hueStep * i;
+ } else {
+ hue = isLight ? hsv.h + hueStep * i : hsv.h - hueStep * i;
+ }
+ if (hue < 0) {
+ hue += 360;
+ } else if (hue >= 360) {
+ hue -= 360;
+ }
+ return Math.round(hue);
+ };
+ var getSaturation = function(hsv, i, isLight) {
+ // grey color don't change saturation
+ if (hsv.h === 0 && hsv.s === 0) {
+ return hsv.s;
+ }
+ var saturation;
+ if (isLight) {
+ saturation = hsv.s - saturationStep * i;
+ } else if (i === darkColorCount) {
+ saturation = hsv.s + saturationStep;
+ } else {
+ saturation = hsv.s + saturationStep2 * i;
+ }
+ if (saturation > 1) {
+ saturation = 1;
+ }
+ if (isLight && i === lightColorCount && saturation > 0.1) {
+ saturation = 0.1;
+ }
+ if (saturation < 0.06) {
+ saturation = 0.06;
+ }
+ return Number(saturation.toFixed(2));
+ };
+ var getValue = function(hsv, i, isLight) {
+ var value;
+ if (isLight) {
+ value = hsv.v + brightnessStep1 * i;
+ }else{
+ value = hsv.v - brightnessStep2 * i
+ }
+ if (value > 1) {
+ value = 1;
+ }
+ return Number(value.toFixed(2))
+ };
+
+ this.colorPalette = function(color, index) {
+ var isLight = index <= 6;
+ var hsv = tinycolor(color).toHsv();
+ var i = isLight ? lightColorCount + 1 - index : index - lightColorCount - 1;
+ return tinycolor({
+ h: getHue(hsv, i, isLight),
+ s: getSaturation(hsv, i, isLight),
+ v: getValue(hsv, i, isLight),
+ }).toHexString();
+ };
+})()`;
+}
+// It is hacky way to make this function will be compiled preferentially by less
+// resolve error: `ReferenceError: colorPalette is not defined`
+// https://github.com/ant-design/ant-motion/issues/44
+.colorPaletteMixin();
diff --git a/webapp/packages/supersonic-fe/src/assets/style/color/colors.less b/webapp/packages/supersonic-fe/src/assets/style/color/colors.less
new file mode 100644
index 000000000..51540bf45
--- /dev/null
+++ b/webapp/packages/supersonic-fe/src/assets/style/color/colors.less
@@ -0,0 +1,162 @@
+@import 'colorPalette';
+
+// color palettes
+@blue-base: #1890ff;
+@blue-1: color(~`colorPalette('@{blue-6}', 1) `);
+@blue-2: color(~`colorPalette('@{blue-6}', 2) `);
+@blue-3: color(~`colorPalette('@{blue-6}', 3) `);
+@blue-4: color(~`colorPalette('@{blue-6}', 4) `);
+@blue-5: color(~`colorPalette('@{blue-6}', 5) `);
+@blue-6: @blue-base;
+@blue-7: color(~`colorPalette('@{blue-6}', 7) `);
+@blue-8: color(~`colorPalette('@{blue-6}', 8) `);
+@blue-9: color(~`colorPalette('@{blue-6}', 9) `);
+@blue-10: color(~`colorPalette('@{blue-6}', 10) `);
+
+@purple-base: #722ed1;
+@purple-1: color(~`colorPalette('@{purple-6}', 1) `);
+@purple-2: color(~`colorPalette('@{purple-6}', 2) `);
+@purple-3: color(~`colorPalette('@{purple-6}', 3) `);
+@purple-4: color(~`colorPalette('@{purple-6}', 4) `);
+@purple-5: color(~`colorPalette('@{purple-6}', 5) `);
+@purple-6: @purple-base;
+@purple-7: color(~`colorPalette('@{purple-6}', 7) `);
+@purple-8: color(~`colorPalette('@{purple-6}', 8) `);
+@purple-9: color(~`colorPalette('@{purple-6}', 9) `);
+@purple-10: color(~`colorPalette('@{purple-6}', 10) `);
+
+@cyan-base: #13c2c2;
+@cyan-1: color(~`colorPalette('@{cyan-6}', 1) `);
+@cyan-2: color(~`colorPalette('@{cyan-6}', 2) `);
+@cyan-3: color(~`colorPalette('@{cyan-6}', 3) `);
+@cyan-4: color(~`colorPalette('@{cyan-6}', 4) `);
+@cyan-5: color(~`colorPalette('@{cyan-6}', 5) `);
+@cyan-6: @cyan-base;
+@cyan-7: color(~`colorPalette('@{cyan-6}', 7) `);
+@cyan-8: color(~`colorPalette('@{cyan-6}', 8) `);
+@cyan-9: color(~`colorPalette('@{cyan-6}', 9) `);
+@cyan-10: color(~`colorPalette('@{cyan-6}', 10) `);
+
+@green-base: #52c41a;
+@green-1: color(~`colorPalette('@{green-6}', 1) `);
+@green-2: color(~`colorPalette('@{green-6}', 2) `);
+@green-3: color(~`colorPalette('@{green-6}', 3) `);
+@green-4: color(~`colorPalette('@{green-6}', 4) `);
+@green-5: color(~`colorPalette('@{green-6}', 5) `);
+@green-6: @green-base;
+@green-7: color(~`colorPalette('@{green-6}', 7) `);
+@green-8: color(~`colorPalette('@{green-6}', 8) `);
+@green-9: color(~`colorPalette('@{green-6}', 9) `);
+@green-10: color(~`colorPalette('@{green-6}', 10) `);
+
+@magenta-base: #eb2f96;
+@magenta-1: color(~`colorPalette('@{magenta-6}', 1) `);
+@magenta-2: color(~`colorPalette('@{magenta-6}', 2) `);
+@magenta-3: color(~`colorPalette('@{magenta-6}', 3) `);
+@magenta-4: color(~`colorPalette('@{magenta-6}', 4) `);
+@magenta-5: color(~`colorPalette('@{magenta-6}', 5) `);
+@magenta-6: @magenta-base;
+@magenta-7: color(~`colorPalette('@{magenta-6}', 7) `);
+@magenta-8: color(~`colorPalette('@{magenta-6}', 8) `);
+@magenta-9: color(~`colorPalette('@{magenta-6}', 9) `);
+@magenta-10: color(~`colorPalette('@{magenta-6}', 10) `);
+
+// alias of magenta
+@pink-base: #eb2f96;
+@pink-1: color(~`colorPalette('@{pink-6}', 1) `);
+@pink-2: color(~`colorPalette('@{pink-6}', 2) `);
+@pink-3: color(~`colorPalette('@{pink-6}', 3) `);
+@pink-4: color(~`colorPalette('@{pink-6}', 4) `);
+@pink-5: color(~`colorPalette('@{pink-6}', 5) `);
+@pink-6: @pink-base;
+@pink-7: color(~`colorPalette('@{pink-6}', 7) `);
+@pink-8: color(~`colorPalette('@{pink-6}', 8) `);
+@pink-9: color(~`colorPalette('@{pink-6}', 9) `);
+@pink-10: color(~`colorPalette('@{pink-6}', 10) `);
+
+@red-base: #f5222d;
+@red-1: color(~`colorPalette('@{red-6}', 1) `);
+@red-2: color(~`colorPalette('@{red-6}', 2) `);
+@red-3: color(~`colorPalette('@{red-6}', 3) `);
+@red-4: color(~`colorPalette('@{red-6}', 4) `);
+@red-5: color(~`colorPalette('@{red-6}', 5) `);
+@red-6: @red-base;
+@red-7: color(~`colorPalette('@{red-6}', 7) `);
+@red-8: color(~`colorPalette('@{red-6}', 8) `);
+@red-9: color(~`colorPalette('@{red-6}', 9) `);
+@red-10: color(~`colorPalette('@{red-6}', 10) `);
+
+@orange-base: #fa8c16;
+@orange-1: color(~`colorPalette('@{orange-6}', 1) `);
+@orange-2: color(~`colorPalette('@{orange-6}', 2) `);
+@orange-3: color(~`colorPalette('@{orange-6}', 3) `);
+@orange-4: color(~`colorPalette('@{orange-6}', 4) `);
+@orange-5: color(~`colorPalette('@{orange-6}', 5) `);
+@orange-6: @orange-base;
+@orange-7: color(~`colorPalette('@{orange-6}', 7) `);
+@orange-8: color(~`colorPalette('@{orange-6}', 8) `);
+@orange-9: color(~`colorPalette('@{orange-6}', 9) `);
+@orange-10: color(~`colorPalette('@{orange-6}', 10) `);
+
+@yellow-base: #fadb14;
+@yellow-1: color(~`colorPalette('@{yellow-6}', 1) `);
+@yellow-2: color(~`colorPalette('@{yellow-6}', 2) `);
+@yellow-3: color(~`colorPalette('@{yellow-6}', 3) `);
+@yellow-4: color(~`colorPalette('@{yellow-6}', 4) `);
+@yellow-5: color(~`colorPalette('@{yellow-6}', 5) `);
+@yellow-6: @yellow-base;
+@yellow-7: color(~`colorPalette('@{yellow-6}', 7) `);
+@yellow-8: color(~`colorPalette('@{yellow-6}', 8) `);
+@yellow-9: color(~`colorPalette('@{yellow-6}', 9) `);
+@yellow-10: color(~`colorPalette('@{yellow-6}', 10) `);
+
+@volcano-base: #fa541c;
+@volcano-1: color(~`colorPalette('@{volcano-6}', 1) `);
+@volcano-2: color(~`colorPalette('@{volcano-6}', 2) `);
+@volcano-3: color(~`colorPalette('@{volcano-6}', 3) `);
+@volcano-4: color(~`colorPalette('@{volcano-6}', 4) `);
+@volcano-5: color(~`colorPalette('@{volcano-6}', 5) `);
+@volcano-6: @volcano-base;
+@volcano-7: color(~`colorPalette('@{volcano-6}', 7) `);
+@volcano-8: color(~`colorPalette('@{volcano-6}', 8) `);
+@volcano-9: color(~`colorPalette('@{volcano-6}', 9) `);
+@volcano-10: color(~`colorPalette('@{volcano-6}', 10) `);
+
+@geekblue-base: #2f54eb;
+@geekblue-1: color(~`colorPalette('@{geekblue-6}', 1) `);
+@geekblue-2: color(~`colorPalette('@{geekblue-6}', 2) `);
+@geekblue-3: color(~`colorPalette('@{geekblue-6}', 3) `);
+@geekblue-4: color(~`colorPalette('@{geekblue-6}', 4) `);
+@geekblue-5: color(~`colorPalette('@{geekblue-6}', 5) `);
+@geekblue-6: @geekblue-base;
+@geekblue-7: color(~`colorPalette('@{geekblue-6}', 7) `);
+@geekblue-8: color(~`colorPalette('@{geekblue-6}', 8) `);
+@geekblue-9: color(~`colorPalette('@{geekblue-6}', 9) `);
+@geekblue-10: color(~`colorPalette('@{geekblue-6}', 10) `);
+
+@lime-base: #a0d911;
+@lime-1: color(~`colorPalette('@{lime-6}', 1) `);
+@lime-2: color(~`colorPalette('@{lime-6}', 2) `);
+@lime-3: color(~`colorPalette('@{lime-6}', 3) `);
+@lime-4: color(~`colorPalette('@{lime-6}', 4) `);
+@lime-5: color(~`colorPalette('@{lime-6}', 5) `);
+@lime-6: @lime-base;
+@lime-7: color(~`colorPalette('@{lime-6}', 7) `);
+@lime-8: color(~`colorPalette('@{lime-6}', 8) `);
+@lime-9: color(~`colorPalette('@{lime-6}', 9) `);
+@lime-10: color(~`colorPalette('@{lime-6}', 10) `);
+
+@gold-base: #faad14;
+@gold-1: color(~`colorPalette('@{gold-6}', 1) `);
+@gold-2: color(~`colorPalette('@{gold-6}', 2) `);
+@gold-3: color(~`colorPalette('@{gold-6}', 3) `);
+@gold-4: color(~`colorPalette('@{gold-6}', 4) `);
+@gold-5: color(~`colorPalette('@{gold-6}', 5) `);
+@gold-6: @gold-base;
+@gold-7: color(~`colorPalette('@{gold-6}', 7) `);
+@gold-8: color(~`colorPalette('@{gold-6}', 8) `);
+@gold-9: color(~`colorPalette('@{gold-6}', 9) `);
+@gold-10: color(~`colorPalette('@{gold-6}', 10) `);
+
+@preset-colors: pink, magenta, red, volcano, orange, yellow, gold, cyan, lime, green, blue, geekblue,
+ purple;
diff --git a/webapp/packages/supersonic-fe/src/assets/style/color/tinyColor.less b/webapp/packages/supersonic-fe/src/assets/style/color/tinyColor.less
new file mode 100644
index 000000000..e576c7868
--- /dev/null
+++ b/webapp/packages/supersonic-fe/src/assets/style/color/tinyColor.less
@@ -0,0 +1,1184 @@
+/* stylelint-disable declaration-bang-space-before,no-duplicate-selectors,string-no-newline */
+.tinyColorMixin() {
+@functions: ~`(function() {
+// TinyColor v1.4.1
+// https://github.com/bgrins/TinyColor
+// 2016-07-07, Brian Grinstead, MIT License
+var trimLeft = /^\s+/,
+ trimRight = /\s+$/,
+ tinyCounter = 0,
+ mathRound = Math.round,
+ mathMin = Math.min,
+ mathMax = Math.max,
+ mathRandom = Math.random;
+
+function tinycolor (color, opts) {
+
+ color = (color) ? color : '';
+ opts = opts || { };
+
+ // If input is already a tinycolor, return itself
+ if (color instanceof tinycolor) {
+ return color;
+ }
+ // If we are called as a function, call using new instead
+ if (!(this instanceof tinycolor)) {
+ return new tinycolor(color, opts);
+ }
+
+ var rgb = inputToRGB(color);
+ this._originalInput = color,
+ this._r = rgb.r,
+ this._g = rgb.g,
+ this._b = rgb.b,
+ this._a = rgb.a,
+ this._roundA = mathRound(100*this._a) / 100,
+ this._format = opts.format || rgb.format;
+ this._gradientType = opts.gradientType;
+
+ // Don't let the range of [0,255] come back in [0,1].
+ // Potentially lose a little bit of precision here, but will fix issues where
+ // .5 gets interpreted as half of the total, instead of half of 1
+ // If it was supposed to be 128, this was already taken care of by inputToRgb
+ if (this._r < 1) { this._r = mathRound(this._r); }
+ if (this._g < 1) { this._g = mathRound(this._g); }
+ if (this._b < 1) { this._b = mathRound(this._b); }
+
+ this._ok = rgb.ok;
+ this._tc_id = tinyCounter++;
+}
+
+tinycolor.prototype = {
+ isDark: function() {
+ return this.getBrightness() < 128;
+ },
+ isLight: function() {
+ return !this.isDark();
+ },
+ isValid: function() {
+ return this._ok;
+ },
+ getOriginalInput: function() {
+ return this._originalInput;
+ },
+ getFormat: function() {
+ return this._format;
+ },
+ getAlpha: function() {
+ return this._a;
+ },
+ getBrightness: function() {
+ //http://www.w3.org/TR/AERT#color-contrast
+ var rgb = this.toRgb();
+ return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
+ },
+ getLuminance: function() {
+ //http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
+ var rgb = this.toRgb();
+ var RsRGB, GsRGB, BsRGB, R, G, B;
+ RsRGB = rgb.r/255;
+ GsRGB = rgb.g/255;
+ BsRGB = rgb.b/255;
+
+ if (RsRGB <= 0.03928) {R = RsRGB / 12.92;} else {R = Math.pow(((RsRGB + 0.055) / 1.055), 2.4);}
+ if (GsRGB <= 0.03928) {G = GsRGB / 12.92;} else {G = Math.pow(((GsRGB + 0.055) / 1.055), 2.4);}
+ if (BsRGB <= 0.03928) {B = BsRGB / 12.92;} else {B = Math.pow(((BsRGB + 0.055) / 1.055), 2.4);}
+ return (0.2126 * R) + (0.7152 * G) + (0.0722 * B);
+ },
+ setAlpha: function(value) {
+ this._a = boundAlpha(value);
+ this._roundA = mathRound(100*this._a) / 100;
+ return this;
+ },
+ toHsv: function() {
+ var hsv = rgbToHsv(this._r, this._g, this._b);
+ return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a };
+ },
+ toHsvString: function() {
+ var hsv = rgbToHsv(this._r, this._g, this._b);
+ var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100);
+ return (this._a == 1) ?
+ "hsv(" + h + ", " + s + "%, " + v + "%)" :
+ "hsva(" + h + ", " + s + "%, " + v + "%, "+ this._roundA + ")";
+ },
+ toHsl: function() {
+ var hsl = rgbToHsl(this._r, this._g, this._b);
+ return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a };
+ },
+ toHslString: function() {
+ var hsl = rgbToHsl(this._r, this._g, this._b);
+ var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100);
+ return (this._a == 1) ?
+ "hsl(" + h + ", " + s + "%, " + l + "%)" :
+ "hsla(" + h + ", " + s + "%, " + l + "%, "+ this._roundA + ")";
+ },
+ toHex: function(allow3Char) {
+ return rgbToHex(this._r, this._g, this._b, allow3Char);
+ },
+ toHexString: function(allow3Char) {
+ return '#' + this.toHex(allow3Char);
+ },
+ toHex8: function(allow4Char) {
+ return rgbaToHex(this._r, this._g, this._b, this._a, allow4Char);
+ },
+ toHex8String: function(allow4Char) {
+ return '#' + this.toHex8(allow4Char);
+ },
+ toRgb: function() {
+ return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a };
+ },
+ toRgbString: function() {
+ return (this._a == 1) ?
+ "rgb(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ")" :
+ "rgba(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ", " + this._roundA + ")";
+ },
+ toPercentageRgb: function() {
+ return { r: mathRound(bound01(this._r, 255) * 100) + "%", g: mathRound(bound01(this._g, 255) * 100) + "%", b: mathRound(bound01(this._b, 255) * 100) + "%", a: this._a };
+ },
+ toPercentageRgbString: function() {
+ return (this._a == 1) ?
+ "rgb(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%)" :
+ "rgba(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%, " + this._roundA + ")";
+ },
+ toName: function() {
+ if (this._a === 0) {
+ return "transparent";
+ }
+
+ if (this._a < 1) {
+ return false;
+ }
+
+ return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false;
+ },
+ toFilter: function(secondColor) {
+ var hex8String = '#' + rgbaToArgbHex(this._r, this._g, this._b, this._a);
+ var secondHex8String = hex8String;
+ var gradientType = this._gradientType ? "GradientType = 1, " : "";
+
+ if (secondColor) {
+ var s = tinycolor(secondColor);
+ secondHex8String = '#' + rgbaToArgbHex(s._r, s._g, s._b, s._a);
+ }
+
+ return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")";
+ },
+ toString: function(format) {
+ var formatSet = !!format;
+ format = format || this._format;
+
+ var formattedString = false;
+ var hasAlpha = this._a < 1 && this._a >= 0;
+ var needsAlphaFormat = !formatSet && hasAlpha && (format === "hex" || format === "hex6" || format === "hex3" || format === "hex4" || format === "hex8" || format === "name");
+
+ if (needsAlphaFormat) {
+ // Special case for "transparent", all other non-alpha formats
+ // will return rgba when there is transparency.
+ if (format === "name" && this._a === 0) {
+ return this.toName();
+ }
+ return this.toRgbString();
+ }
+ if (format === "rgb") {
+ formattedString = this.toRgbString();
+ }
+ if (format === "prgb") {
+ formattedString = this.toPercentageRgbString();
+ }
+ if (format === "hex" || format === "hex6") {
+ formattedString = this.toHexString();
+ }
+ if (format === "hex3") {
+ formattedString = this.toHexString(true);
+ }
+ if (format === "hex4") {
+ formattedString = this.toHex8String(true);
+ }
+ if (format === "hex8") {
+ formattedString = this.toHex8String();
+ }
+ if (format === "name") {
+ formattedString = this.toName();
+ }
+ if (format === "hsl") {
+ formattedString = this.toHslString();
+ }
+ if (format === "hsv") {
+ formattedString = this.toHsvString();
+ }
+
+ return formattedString || this.toHexString();
+ },
+ clone: function() {
+ return tinycolor(this.toString());
+ },
+
+ _applyModification: function(fn, args) {
+ var color = fn.apply(null, [this].concat([].slice.call(args)));
+ this._r = color._r;
+ this._g = color._g;
+ this._b = color._b;
+ this.setAlpha(color._a);
+ return this;
+ },
+ lighten: function() {
+ return this._applyModification(lighten, arguments);
+ },
+ brighten: function() {
+ return this._applyModification(brighten, arguments);
+ },
+ darken: function() {
+ return this._applyModification(darken, arguments);
+ },
+ desaturate: function() {
+ return this._applyModification(desaturate, arguments);
+ },
+ saturate: function() {
+ return this._applyModification(saturate, arguments);
+ },
+ greyscale: function() {
+ return this._applyModification(greyscale, arguments);
+ },
+ spin: function() {
+ return this._applyModification(spin, arguments);
+ },
+
+ _applyCombination: function(fn, args) {
+ return fn.apply(null, [this].concat([].slice.call(args)));
+ },
+ analogous: function() {
+ return this._applyCombination(analogous, arguments);
+ },
+ complement: function() {
+ return this._applyCombination(complement, arguments);
+ },
+ monochromatic: function() {
+ return this._applyCombination(monochromatic, arguments);
+ },
+ splitcomplement: function() {
+ return this._applyCombination(splitcomplement, arguments);
+ },
+ triad: function() {
+ return this._applyCombination(triad, arguments);
+ },
+ tetrad: function() {
+ return this._applyCombination(tetrad, arguments);
+ }
+};
+
+// If input is an object, force 1 into "1.0" to handle ratios properly
+// String input requires "1.0" as input, so 1 will be treated as 1
+tinycolor.fromRatio = function(color, opts) {
+ if (typeof color == "object") {
+ var newColor = {};
+ for (var i in color) {
+ if (color.hasOwnProperty(i)) {
+ if (i === "a") {
+ newColor[i] = color[i];
+ }
+ else {
+ newColor[i] = convertToPercentage(color[i]);
+ }
+ }
+ }
+ color = newColor;
+ }
+
+ return tinycolor(color, opts);
+};
+
+// Given a string or object, convert that input to RGB
+// Possible string inputs:
+//
+// "red"
+// "#f00" or "f00"
+// "#ff0000" or "ff0000"
+// "#ff000000" or "ff000000"
+// "rgb 255 0 0" or "rgb (255, 0, 0)"
+// "rgb 1.0 0 0" or "rgb (1, 0, 0)"
+// "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
+// "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1"
+// "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
+// "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
+// "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
+//
+function inputToRGB(color) {
+
+ var rgb = { r: 0, g: 0, b: 0 };
+ var a = 1;
+ var s = null;
+ var v = null;
+ var l = null;
+ var ok = false;
+ var format = false;
+
+ if (typeof color == "string") {
+ color = stringInputToObject(color);
+ }
+
+ if (typeof color == "object") {
+ if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) {
+ rgb = rgbToRgb(color.r, color.g, color.b);
+ ok = true;
+ format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb";
+ }
+ else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
+ s = convertToPercentage(color.s);
+ v = convertToPercentage(color.v);
+ rgb = hsvToRgb(color.h, s, v);
+ ok = true;
+ format = "hsv";
+ }
+ else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) {
+ s = convertToPercentage(color.s);
+ l = convertToPercentage(color.l);
+ rgb = hslToRgb(color.h, s, l);
+ ok = true;
+ format = "hsl";
+ }
+
+ if (color.hasOwnProperty("a")) {
+ a = color.a;
+ }
+ }
+
+ a = boundAlpha(a);
+
+ return {
+ ok: ok,
+ format: color.format || format,
+ r: mathMin(255, mathMax(rgb.r, 0)),
+ g: mathMin(255, mathMax(rgb.g, 0)),
+ b: mathMin(255, mathMax(rgb.b, 0)),
+ a: a
+ };
+}
+
+// Conversion Functions
+// --------------------
+
+// rgbToHsl, rgbToHsv, hslToRgb, hsvToRgb modified from:
+//
+
+// rgbToRgb
+// Handle bounds / percentage checking to conform to CSS color spec
+//
+// *Assumes:* r, g, b in [0, 255] or [0, 1]
+// *Returns:* { r, g, b } in [0, 255]
+function rgbToRgb(r, g, b){
+ return {
+ r: bound01(r, 255) * 255,
+ g: bound01(g, 255) * 255,
+ b: bound01(b, 255) * 255
+ };
+}
+
+// rgbToHsl
+// Converts an RGB color value to HSL.
+// *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]
+// *Returns:* { h, s, l } in [0,1]
+function rgbToHsl(r, g, b) {
+
+ r = bound01(r, 255);
+ g = bound01(g, 255);
+ b = bound01(b, 255);
+
+ var max = mathMax(r, g, b), min = mathMin(r, g, b);
+ var h, s, l = (max + min) / 2;
+
+ if(max == min) {
+ h = s = 0; // achromatic
+ }
+ else {
+ var d = max - min;
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
+ switch(max) {
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+
+ h /= 6;
+ }
+
+ return { h: h, s: s, l: l };
+}
+
+// hslToRgb
+// Converts an HSL color value to RGB.
+// *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
+// *Returns:* { r, g, b } in the set [0, 255]
+function hslToRgb(h, s, l) {
+ var r, g, b;
+
+ h = bound01(h, 360);
+ s = bound01(s, 100);
+ l = bound01(l, 100);
+
+ function hue2rgb(p, q, t) {
+ if(t < 0) t += 1;
+ if(t > 1) t -= 1;
+ if(t < 1/6) return p + (q - p) * 6 * t;
+ if(t < 1/2) return q;
+ if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
+ return p;
+ }
+
+ if(s === 0) {
+ r = g = b = l; // achromatic
+ }
+ else {
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+ var p = 2 * l - q;
+ r = hue2rgb(p, q, h + 1/3);
+ g = hue2rgb(p, q, h);
+ b = hue2rgb(p, q, h - 1/3);
+ }
+
+ return { r: r * 255, g: g * 255, b: b * 255 };
+}
+
+// rgbToHsv
+// Converts an RGB color value to HSV
+// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
+// *Returns:* { h, s, v } in [0,1]
+function rgbToHsv(r, g, b) {
+
+ r = bound01(r, 255);
+ g = bound01(g, 255);
+ b = bound01(b, 255);
+
+ var max = mathMax(r, g, b), min = mathMin(r, g, b);
+ var h, s, v = max;
+
+ var d = max - min;
+ s = max === 0 ? 0 : d / max;
+
+ if(max == min) {
+ h = 0; // achromatic
+ }
+ else {
+ switch(max) {
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+ return { h: h, s: s, v: v };
+}
+
+// hsvToRgb
+// Converts an HSV color value to RGB.
+// *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
+// *Returns:* { r, g, b } in the set [0, 255]
+ function hsvToRgb(h, s, v) {
+
+ h = bound01(h, 360) * 6;
+ s = bound01(s, 100);
+ v = bound01(v, 100);
+
+ var i = Math.floor(h),
+ f = h - i,
+ p = v * (1 - s),
+ q = v * (1 - f * s),
+ t = v * (1 - (1 - f) * s),
+ mod = i % 6,
+ r = [v, q, p, p, t, v][mod],
+ g = [t, v, v, q, p, p][mod],
+ b = [p, p, t, v, v, q][mod];
+
+ return { r: r * 255, g: g * 255, b: b * 255 };
+}
+
+// rgbToHex
+// Converts an RGB color to hex
+// Assumes r, g, and b are contained in the set [0, 255]
+// Returns a 3 or 6 character hex
+function rgbToHex(r, g, b, allow3Char) {
+
+ var hex = [
+ pad2(mathRound(r).toString(16)),
+ pad2(mathRound(g).toString(16)),
+ pad2(mathRound(b).toString(16))
+ ];
+
+ // Return a 3 character hex if possible
+ if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) {
+ return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
+ }
+
+ return hex.join("");
+}
+
+// rgbaToHex
+// Converts an RGBA color plus alpha transparency to hex
+// Assumes r, g, b are contained in the set [0, 255] and
+// a in [0, 1]. Returns a 4 or 8 character rgba hex
+function rgbaToHex(r, g, b, a, allow4Char) {
+
+ var hex = [
+ pad2(mathRound(r).toString(16)),
+ pad2(mathRound(g).toString(16)),
+ pad2(mathRound(b).toString(16)),
+ pad2(convertDecimalToHex(a))
+ ];
+
+ // Return a 4 character hex if possible
+ if (allow4Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1) && hex[3].charAt(0) == hex[3].charAt(1)) {
+ return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0);
+ }
+
+ return hex.join("");
+}
+
+// rgbaToArgbHex
+// Converts an RGBA color to an ARGB Hex8 string
+// Rarely used, but required for "toFilter()"
+function rgbaToArgbHex(r, g, b, a) {
+
+ var hex = [
+ pad2(convertDecimalToHex(a)),
+ pad2(mathRound(r).toString(16)),
+ pad2(mathRound(g).toString(16)),
+ pad2(mathRound(b).toString(16))
+ ];
+
+ return hex.join("");
+}
+
+// equals
+// Can be called with any tinycolor input
+tinycolor.equals = function (color1, color2) {
+ if (!color1 || !color2) { return false; }
+ return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString();
+};
+
+tinycolor.random = function() {
+ return tinycolor.fromRatio({
+ r: mathRandom(),
+ g: mathRandom(),
+ b: mathRandom()
+ });
+};
+
+// Modification Functions
+// ----------------------
+// Thanks to less.js for some of the basics here
+//
+
+function desaturate(color, amount) {
+ amount = (amount === 0) ? 0 : (amount || 10);
+ var hsl = tinycolor(color).toHsl();
+ hsl.s -= amount / 100;
+ hsl.s = clamp01(hsl.s);
+ return tinycolor(hsl);
+}
+
+function saturate(color, amount) {
+ amount = (amount === 0) ? 0 : (amount || 10);
+ var hsl = tinycolor(color).toHsl();
+ hsl.s += amount / 100;
+ hsl.s = clamp01(hsl.s);
+ return tinycolor(hsl);
+}
+
+function greyscale(color) {
+ return tinycolor(color).desaturate(100);
+}
+
+function lighten (color, amount) {
+ amount = (amount === 0) ? 0 : (amount || 10);
+ var hsl = tinycolor(color).toHsl();
+ hsl.l += amount / 100;
+ hsl.l = clamp01(hsl.l);
+ return tinycolor(hsl);
+}
+
+function brighten(color, amount) {
+ amount = (amount === 0) ? 0 : (amount || 10);
+ var rgb = tinycolor(color).toRgb();
+ rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * - (amount / 100))));
+ rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * - (amount / 100))));
+ rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * - (amount / 100))));
+ return tinycolor(rgb);
+}
+
+function darken (color, amount) {
+ amount = (amount === 0) ? 0 : (amount || 10);
+ var hsl = tinycolor(color).toHsl();
+ hsl.l -= amount / 100;
+ hsl.l = clamp01(hsl.l);
+ return tinycolor(hsl);
+}
+
+// Spin takes a positive or negative amount within [-360, 360] indicating the change of hue.
+// Values outside of this range will be wrapped into this range.
+function spin(color, amount) {
+ var hsl = tinycolor(color).toHsl();
+ var hue = (hsl.h + amount) % 360;
+ hsl.h = hue < 0 ? 360 + hue : hue;
+ return tinycolor(hsl);
+}
+
+// Combination Functions
+// ---------------------
+// Thanks to jQuery xColor for some of the ideas behind these
+//
+
+function complement(color) {
+ var hsl = tinycolor(color).toHsl();
+ hsl.h = (hsl.h + 180) % 360;
+ return tinycolor(hsl);
+}
+
+function triad(color) {
+ var hsl = tinycolor(color).toHsl();
+ var h = hsl.h;
+ return [
+ tinycolor(color),
+ tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }),
+ tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l })
+ ];
+}
+
+function tetrad(color) {
+ var hsl = tinycolor(color).toHsl();
+ var h = hsl.h;
+ return [
+ tinycolor(color),
+ tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }),
+ tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }),
+ tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l })
+ ];
+}
+
+function splitcomplement(color) {
+ var hsl = tinycolor(color).toHsl();
+ var h = hsl.h;
+ return [
+ tinycolor(color),
+ tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}),
+ tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l})
+ ];
+}
+
+function analogous(color, results, slices) {
+ results = results || 6;
+ slices = slices || 30;
+
+ var hsl = tinycolor(color).toHsl();
+ var part = 360 / slices;
+ var ret = [tinycolor(color)];
+
+ for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) {
+ hsl.h = (hsl.h + part) % 360;
+ ret.push(tinycolor(hsl));
+ }
+ return ret;
+}
+
+function monochromatic(color, results) {
+ results = results || 6;
+ var hsv = tinycolor(color).toHsv();
+ var h = hsv.h, s = hsv.s, v = hsv.v;
+ var ret = [];
+ var modification = 1 / results;
+
+ while (results--) {
+ ret.push(tinycolor({ h: h, s: s, v: v}));
+ v = (v + modification) % 1;
+ }
+
+ return ret;
+}
+
+// Utility Functions
+// ---------------------
+
+tinycolor.mix = function(color1, color2, amount) {
+ amount = (amount === 0) ? 0 : (amount || 50);
+
+ var rgb1 = tinycolor(color1).toRgb();
+ var rgb2 = tinycolor(color2).toRgb();
+
+ var p = amount / 100;
+
+ var rgba = {
+ r: ((rgb2.r - rgb1.r) * p) + rgb1.r,
+ g: ((rgb2.g - rgb1.g) * p) + rgb1.g,
+ b: ((rgb2.b - rgb1.b) * p) + rgb1.b,
+ a: ((rgb2.a - rgb1.a) * p) + rgb1.a
+ };
+
+ return tinycolor(rgba);
+};
+
+// Readability Functions
+// ---------------------
+// false
+// tinycolor.isReadable("#000", "#111",{level:"AA",size:"large"}) => false
+tinycolor.isReadable = function(color1, color2, wcag2) {
+ var readability = tinycolor.readability(color1, color2);
+ var wcag2Parms, out;
+
+ out = false;
+
+ wcag2Parms = validateWCAG2Parms(wcag2);
+ switch (wcag2Parms.level + wcag2Parms.size) {
+ case "AAsmall":
+ case "AAAlarge":
+ out = readability >= 4.5;
+ break;
+ case "AAlarge":
+ out = readability >= 3;
+ break;
+ case "AAAsmall":
+ out = readability >= 7;
+ break;
+ }
+ return out;
+
+};
+
+// mostReadable
+// Given a base color and a list of possible foreground or background
+// colors for that base, returns the most readable color.
+// Optionally returns Black or White if the most readable color is unreadable.
+// *Example*
+// tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:false}).toHexString(); // "#112255"
+// tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:true}).toHexString(); // "#ffffff"
+// tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"large"}).toHexString(); // "#faf3f3"
+// tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"small"}).toHexString(); // "#ffffff"
+tinycolor.mostReadable = function(baseColor, colorList, args) {
+ var bestColor = null;
+ var bestScore = 0;
+ var readability;
+ var includeFallbackColors, level, size ;
+ args = args || {};
+ includeFallbackColors = args.includeFallbackColors ;
+ level = args.level;
+ size = args.size;
+
+ for (var i= 0; i < colorList.length ; i++) {
+ readability = tinycolor.readability(baseColor, colorList[i]);
+ if (readability > bestScore) {
+ bestScore = readability;
+ bestColor = tinycolor(colorList[i]);
+ }
+ }
+
+ if (tinycolor.isReadable(baseColor, bestColor, {"level":level,"size":size}) || !includeFallbackColors) {
+ return bestColor;
+ }
+ else {
+ args.includeFallbackColors=false;
+ return tinycolor.mostReadable(baseColor,["#fff", "#000"],args);
+ }
+};
+
+// Big List of Colors
+// ------------------
+//
+var names = tinycolor.names = {
+ aliceblue: "f0f8ff",
+ antiquewhite: "faebd7",
+ aqua: "0ff",
+ aquamarine: "7fffd4",
+ azure: "f0ffff",
+ beige: "f5f5dc",
+ bisque: "ffe4c4",
+ black: "000",
+ blanchedalmond: "ffebcd",
+ blue: "00f",
+ blueviolet: "8a2be2",
+ brown: "a52a2a",
+ burlywood: "deb887",
+ burntsienna: "ea7e5d",
+ cadetblue: "5f9ea0",
+ chartreuse: "7fff00",
+ chocolate: "d2691e",
+ coral: "ff7f50",
+ cornflowerblue: "6495ed",
+ cornsilk: "fff8dc",
+ crimson: "dc143c",
+ cyan: "0ff",
+ darkblue: "00008b",
+ darkcyan: "008b8b",
+ darkgoldenrod: "b8860b",
+ darkgray: "a9a9a9",
+ darkgreen: "006400",
+ darkgrey: "a9a9a9",
+ darkkhaki: "bdb76b",
+ darkmagenta: "8b008b",
+ darkolivegreen: "556b2f",
+ darkorange: "ff8c00",
+ darkorchid: "9932cc",
+ darkred: "8b0000",
+ darksalmon: "e9967a",
+ darkseagreen: "8fbc8f",
+ darkslateblue: "483d8b",
+ darkslategray: "2f4f4f",
+ darkslategrey: "2f4f4f",
+ darkturquoise: "00ced1",
+ darkviolet: "9400d3",
+ deeppink: "ff1493",
+ deepskyblue: "00bfff",
+ dimgray: "696969",
+ dimgrey: "696969",
+ dodgerblue: "1e90ff",
+ firebrick: "b22222",
+ floralwhite: "fffaf0",
+ forestgreen: "228b22",
+ fuchsia: "f0f",
+ gainsboro: "dcdcdc",
+ ghostwhite: "f8f8ff",
+ gold: "ffd700",
+ goldenrod: "daa520",
+ gray: "808080",
+ green: "008000",
+ greenyellow: "adff2f",
+ grey: "808080",
+ honeydew: "f0fff0",
+ hotpink: "ff69b4",
+ indianred: "cd5c5c",
+ indigo: "4b0082",
+ ivory: "fffff0",
+ khaki: "f0e68c",
+ lavender: "e6e6fa",
+ lavenderblush: "fff0f5",
+ lawngreen: "7cfc00",
+ lemonchiffon: "fffacd",
+ lightblue: "add8e6",
+ lightcoral: "f08080",
+ lightcyan: "e0ffff",
+ lightgoldenrodyellow: "fafad2",
+ lightgray: "d3d3d3",
+ lightgreen: "90ee90",
+ lightgrey: "d3d3d3",
+ lightpink: "ffb6c1",
+ lightsalmon: "ffa07a",
+ lightseagreen: "20b2aa",
+ lightskyblue: "87cefa",
+ lightslategray: "789",
+ lightslategrey: "789",
+ lightsteelblue: "b0c4de",
+ lightyellow: "ffffe0",
+ lime: "0f0",
+ limegreen: "32cd32",
+ linen: "faf0e6",
+ magenta: "f0f",
+ maroon: "800000",
+ mediumaquamarine: "66cdaa",
+ mediumblue: "0000cd",
+ mediumorchid: "ba55d3",
+ mediumpurple: "9370db",
+ mediumseagreen: "3cb371",
+ mediumslateblue: "7b68ee",
+ mediumspringgreen: "00fa9a",
+ mediumturquoise: "48d1cc",
+ mediumvioletred: "c71585",
+ midnightblue: "191970",
+ mintcream: "f5fffa",
+ mistyrose: "ffe4e1",
+ moccasin: "ffe4b5",
+ navajowhite: "ffdead",
+ navy: "000080",
+ oldlace: "fdf5e6",
+ olive: "808000",
+ olivedrab: "6b8e23",
+ orange: "ffa500",
+ orangered: "ff4500",
+ orchid: "da70d6",
+ palegoldenrod: "eee8aa",
+ palegreen: "98fb98",
+ paleturquoise: "afeeee",
+ palevioletred: "db7093",
+ papayawhip: "ffefd5",
+ peachpuff: "ffdab9",
+ peru: "cd853f",
+ pink: "ffc0cb",
+ plum: "dda0dd",
+ powderblue: "b0e0e6",
+ purple: "800080",
+ rebeccapurple: "663399",
+ red: "f00",
+ rosybrown: "bc8f8f",
+ royalblue: "4169e1",
+ saddlebrown: "8b4513",
+ salmon: "fa8072",
+ sandybrown: "f4a460",
+ seagreen: "2e8b57",
+ seashell: "fff5ee",
+ sienna: "a0522d",
+ silver: "c0c0c0",
+ skyblue: "87ceeb",
+ slateblue: "6a5acd",
+ slategray: "708090",
+ slategrey: "708090",
+ snow: "fffafa",
+ springgreen: "00ff7f",
+ steelblue: "4682b4",
+ tan: "d2b48c",
+ teal: "008080",
+ thistle: "d8bfd8",
+ tomato: "ff6347",
+ turquoise: "40e0d0",
+ violet: "ee82ee",
+ wheat: "f5deb3",
+ white: "fff",
+ whitesmoke: "f5f5f5",
+ yellow: "ff0",
+ yellowgreen: "9acd32"
+};
+
+// Make it easy to access colors via hexNames[hex]
+var hexNames = tinycolor.hexNames = flip(names);
+
+// Utilities
+// ---------
+
+// { 'name1': 'val1' } becomes { 'val1': 'name1' }
+function flip(o) {
+ var flipped = { };
+ for (var i in o) {
+ if (o.hasOwnProperty(i)) {
+ flipped[o[i]] = i;
+ }
+ }
+ return flipped;
+}
+
+// Return a valid alpha value [0,1] with all invalid values being set to 1
+function boundAlpha(a) {
+ a = parseFloat(a);
+
+ if (isNaN(a) || a < 0 || a > 1) {
+ a = 1;
+ }
+
+ return a;
+}
+
+// Take input from [0, n] and return it as [0, 1]
+function bound01(n, max) {
+ if (isOnePointZero(n)) { n = "100%"; }
+
+ var processPercent = isPercentage(n);
+ n = mathMin(max, mathMax(0, parseFloat(n)));
+
+ // Automatically convert percentage into number
+ if (processPercent) {
+ n = parseInt(n * max, 10) / 100;
+ }
+
+ // Handle floating point rounding errors
+ if ((Math.abs(n - max) < 0.000001)) {
+ return 1;
+ }
+
+ // Convert into [0, 1] range if it isn't already
+ return (n % max) / parseFloat(max);
+}
+
+// Force a number between 0 and 1
+function clamp01(val) {
+ return mathMin(1, mathMax(0, val));
+}
+
+// Parse a base-16 hex value into a base-10 integer
+function parseIntFromHex(val) {
+ return parseInt(val, 16);
+}
+
+// Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
+//
+function isOnePointZero(n) {
+ return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1;
+}
+
+// Check to see if string passed in is a percentage
+function isPercentage(n) {
+ return typeof n === "string" && n.indexOf('%') != -1;
+}
+
+// Force a hex value to have 2 characters
+function pad2(c) {
+ return c.length == 1 ? '0' + c : '' + c;
+}
+
+// Replace a decimal with it's percentage value
+function convertToPercentage(n) {
+ if (n <= 1) {
+ n = (n * 100) + "%";
+ }
+
+ return n;
+}
+
+// Converts a decimal to a hex value
+function convertDecimalToHex(d) {
+ return Math.round(parseFloat(d) * 255).toString(16);
+}
+// Converts a hex value to a decimal
+function convertHexToDecimal(h) {
+ return (parseIntFromHex(h) / 255);
+}
+
+var matchers = (function() {
+
+ //
+ var CSS_INTEGER = "[-\\+]?\\d+%?";
+
+ //
+ var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?";
+
+ // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome.
+ var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")";
+
+ // Actual matching.
+ // Parentheses and commas are optional, but not required.
+ // Whitespace can take the place of commas or opening paren
+ var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
+ var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
+
+ return {
+ CSS_UNIT: new RegExp(CSS_UNIT),
+ rgb: new RegExp("rgb" + PERMISSIVE_MATCH3),
+ rgba: new RegExp("rgba" + PERMISSIVE_MATCH4),
+ hsl: new RegExp("hsl" + PERMISSIVE_MATCH3),
+ hsla: new RegExp("hsla" + PERMISSIVE_MATCH4),
+ hsv: new RegExp("hsv" + PERMISSIVE_MATCH3),
+ hsva: new RegExp("hsva" + PERMISSIVE_MATCH4),
+ hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
+ hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
+ hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
+ hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/
+ };
+})();
+
+// isValidCSSUnit
+// Take in a single string / number and check to see if it looks like a CSS unit
+// (see matchers above for definition).
+function isValidCSSUnit(color) {
+ return !!matchers.CSS_UNIT.exec(color);
+}
+
+// stringInputToObject
+// Permissive string parsing. Take in a number of formats, and output an object
+// based on detected format. Returns { r, g, b } or { h, s, l } or { h, s, v}
+function stringInputToObject(color) {
+
+ color = color.replace(trimLeft, '').replace(trimRight, '').toLowerCase();
+ var named = false;
+ if (names[color]) {
+ color = names[color];
+ named = true;
+ }
+ else if (color == 'transparent') {
+ return { r: 0, g: 0, b: 0, a: 0, format: "name" };
+ }
+
+ // Try to match string input using regular expressions.
+ // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]
+ // Just return an object and let the conversion functions handle that.
+ // This way the result will be the same whether the tinycolor is initialized with string or object.
+ var match;
+ if ((match = matchers.rgb.exec(color))) {
+ return { r: match[1], g: match[2], b: match[3] };
+ }
+ if ((match = matchers.rgba.exec(color))) {
+ return { r: match[1], g: match[2], b: match[3], a: match[4] };
+ }
+ if ((match = matchers.hsl.exec(color))) {
+ return { h: match[1], s: match[2], l: match[3] };
+ }
+ if ((match = matchers.hsla.exec(color))) {
+ return { h: match[1], s: match[2], l: match[3], a: match[4] };
+ }
+ if ((match = matchers.hsv.exec(color))) {
+ return { h: match[1], s: match[2], v: match[3] };
+ }
+ if ((match = matchers.hsva.exec(color))) {
+ return { h: match[1], s: match[2], v: match[3], a: match[4] };
+ }
+ if ((match = matchers.hex8.exec(color))) {
+ return {
+ r: parseIntFromHex(match[1]),
+ g: parseIntFromHex(match[2]),
+ b: parseIntFromHex(match[3]),
+ a: convertHexToDecimal(match[4]),
+ format: named ? "name" : "hex8"
+ };
+ }
+ if ((match = matchers.hex6.exec(color))) {
+ return {
+ r: parseIntFromHex(match[1]),
+ g: parseIntFromHex(match[2]),
+ b: parseIntFromHex(match[3]),
+ format: named ? "name" : "hex"
+ };
+ }
+ if ((match = matchers.hex4.exec(color))) {
+ return {
+ r: parseIntFromHex(match[1] + '' + match[1]),
+ g: parseIntFromHex(match[2] + '' + match[2]),
+ b: parseIntFromHex(match[3] + '' + match[3]),
+ a: convertHexToDecimal(match[4] + '' + match[4]),
+ format: named ? "name" : "hex8"
+ };
+ }
+ if ((match = matchers.hex3.exec(color))) {
+ return {
+ r: parseIntFromHex(match[1] + '' + match[1]),
+ g: parseIntFromHex(match[2] + '' + match[2]),
+ b: parseIntFromHex(match[3] + '' + match[3]),
+ format: named ? "name" : "hex"
+ };
+ }
+
+ return false;
+}
+
+function validateWCAG2Parms(parms) {
+ // return valid WCAG2 parms for isReadable.
+ // If input parms are invalid, return {"level":"AA", "size":"small"}
+ var level, size;
+ parms = parms || {"level":"AA", "size":"small"};
+ level = (parms.level || "AA").toUpperCase();
+ size = (parms.size || "small").toLowerCase();
+ if (level !== "AA" && level !== "AAA") {
+ level = "AA";
+ }
+ if (size !== "small" && size !== "large") {
+ size = "small";
+ }
+ return {"level":level, "size":size};
+}
+
+this.tinycolor = tinycolor;
+
+})()`;
+}
+// It is hacky way to make this function will be compiled preferentially by less
+// resolve error: `ReferenceError: colorPalette is not defined`
+// https://github.com/ant-design/ant-motion/issues/44
+.tinyColorMixin();
diff --git a/webapp/packages/supersonic-fe/src/assets/style/compact.less b/webapp/packages/supersonic-fe/src/assets/style/compact.less
new file mode 100644
index 000000000..ef0008ba3
--- /dev/null
+++ b/webapp/packages/supersonic-fe/src/assets/style/compact.less
@@ -0,0 +1,4 @@
+@root-entry-name: default;
+
+@import './themes/compact.less';
+@import './core/index';
diff --git a/webapp/packages/supersonic-fe/src/assets/style/core/base.less b/webapp/packages/supersonic-fe/src/assets/style/core/base.less
new file mode 100644
index 000000000..a704c5512
--- /dev/null
+++ b/webapp/packages/supersonic-fe/src/assets/style/core/base.less
@@ -0,0 +1,10 @@
+// Config global less under antd
+[class^=~'@{ant-prefix}-'],
+[class*=~' @{ant-prefix}-'] {
+ // remove the clear button of a text input control in IE10+
+ &::-ms-clear,
+ input::-ms-clear,
+ input::-ms-reveal {
+ display: none;
+ }
+}
diff --git a/webapp/packages/supersonic-fe/src/assets/style/core/global.less b/webapp/packages/supersonic-fe/src/assets/style/core/global.less
new file mode 100644
index 000000000..cb26cce38
--- /dev/null
+++ b/webapp/packages/supersonic-fe/src/assets/style/core/global.less
@@ -0,0 +1,491 @@
+/* stylelint-disable property-no-vendor-prefix, at-rule-no-vendor-prefix */
+
+// Reboot
+//
+// Normalization of HTML elements, manually forked from Normalize.css to remove
+// styles targeting irrelevant browsers while applying new styles.
+//
+// Normalize is licensed MIT. https://github.com/necolas/normalize.css
+
+// HTML & Body reset
+@{html-selector},
+body {
+ .square(100%);
+}
+
+// remove the clear button of a text input control in IE10+
+input::-ms-clear,
+input::-ms-reveal {
+ display: none;
+}
+
+// Document
+//
+// 1. Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.
+// 2. Change the default font family in all browsers.
+// 3. Correct the line height in all browsers.
+// 4. Prevent adjustments of font size after orientation changes in IE on Windows Phone and in iOS.
+// 5. Setting @viewport causes scrollbars to overlap content in IE11 and Edge, so
+// we force a non-overlapping, non-auto-hiding scrollbar to counteract.
+// 6. Change the default tap highlight to be completely transparent in iOS.
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box; // 1
+}
+
+@{html-selector} {
+ font-family: sans-serif; // 2
+ line-height: 1.15; // 3
+ -webkit-text-size-adjust: 100%; // 4
+ -ms-text-size-adjust: 100%; // 4
+ -ms-overflow-style: scrollbar; // 5
+ -webkit-tap-highlight-color: fade(@black, 0%); // 6
+}
+
+// IE10+ doesn't honor `` in some cases.
+@-ms-viewport {
+ width: device-width;
+}
+
+// Body
+//
+// 1. remove the margin in all browsers.
+// 2. As a best practice, apply a default `body-background`.
+
+body {
+ margin: 0; // 1
+ color: @text-color;
+ font-size: @font-size-base;
+ font-family: @font-family;
+ font-variant: @font-variant-base;
+ line-height: @line-height-base;
+ background-color: @body-background; // 2
+ font-feature-settings: @font-feature-settings-base;
+}
+
+// Suppress the focus outline on elements that cannot be accessed via keyboard.
+// This prevents an unwanted focus outline from appearing around elements that
+// might still respond to pointer events.
+//
+// Credit: https://github.com/suitcss/base
+[tabindex='-1']:focus {
+ outline: none !important;
+}
+
+// Content grouping
+//
+// 1. Add the correct box sizing in Firefox.
+// 2. Show the overflow in Edge and IE.
+
+hr {
+ box-sizing: content-box; // 1
+ height: 0; // 1
+ overflow: visible; // 2
+}
+
+//
+// Typography
+//
+
+// remove top margins from headings
+//
+// By default, `
`-`
` all receive top and bottom margins. We nuke the top
+// margin for easier control within type scales as it avoids margin collapsing.
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ margin-top: 0;
+ margin-bottom: 0.5em;
+ color: @heading-color;
+ font-weight: 500;
+}
+
+// Reset margins on paragraphs
+//
+// Similarly, the top margin on `
`s get reset. However, we also reset the
+// bottom margin to use `em` units instead of `em`.
+p {
+ margin-top: 0;
+ margin-bottom: 1em;
+}
+
+// Abbreviations
+//
+// 1. remove the bottom border in Firefox 39-.
+// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+// 3. Add explicit cursor to indicate changed behavior.
+// 4. Duplicate behavior to the data-* attribute for our tooltip plugin
+
+abbr[title],
+abbr[data-original-title] {
+ // 4
+ text-decoration: underline; // 2
+ text-decoration: underline dotted; // 2
+ border-bottom: 0; // 1
+ cursor: help; // 3
+}
+
+address {
+ margin-bottom: 1em;
+ font-style: normal;
+ line-height: inherit;
+}
+
+input[type='text'],
+input[type='password'],
+input[type='number'],
+textarea {
+ -webkit-appearance: none;
+}
+
+ol,
+ul,
+dl {
+ margin-top: 0;
+ margin-bottom: 1em;
+}
+
+ol ol,
+ul ul,
+ol ul,
+ul ol {
+ margin-bottom: 0;
+}
+
+dt {
+ font-weight: 500;
+}
+
+dd {
+ margin-bottom: 0.5em;
+ margin-left: 0; // Undo browser default
+}
+
+blockquote {
+ margin: 0 0 1em;
+}
+
+dfn {
+ font-style: italic; // Add the correct font style in Android 4.3-
+}
+
+b,
+strong {
+ font-weight: bolder; // Add the correct font weight in Chrome, Edge, and Safari
+}
+
+small {
+ font-size: 80%; // Add the correct font size in all browsers
+}
+
+//
+// Prevent `sub` and `sup` elements from affecting the line height in
+// all browsers.
+//
+
+sub,
+sup {
+ position: relative;
+ font-size: 75%;
+ line-height: 0;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+//
+// Links
+//
+
+a {
+ color: @link-color;
+ text-decoration: @link-decoration;
+ background-color: transparent; // remove the gray background on active links in IE 10.
+ outline: none;
+ cursor: pointer;
+ transition: color 0.3s;
+ -webkit-text-decoration-skip: objects; // remove gaps in links underline in iOS 8+ and Safari 8+.
+
+ &:hover {
+ color: @link-hover-color;
+ }
+
+ &:active {
+ color: @link-active-color;
+ }
+
+ &:active,
+ &:hover {
+ text-decoration: @link-hover-decoration;
+ outline: 0;
+ }
+
+ // https://github.com/ant-design/ant-design/issues/22503
+ &:focus {
+ text-decoration: @link-focus-decoration;
+ outline: @link-focus-outline;
+ }
+
+ &[disabled] {
+ color: @disabled-color;
+ cursor: not-allowed;
+ }
+}
+
+//
+// Code
+//
+
+pre,
+code,
+kbd,
+samp {
+ font-size: 1em; // Correct the odd `em` font sizing in all browsers.
+ font-family: @code-family;
+}
+
+pre {
+ // remove browser default top margin
+ margin-top: 0;
+ // Reset browser default of `1em` to use `em`s
+ margin-bottom: 1em;
+ // Don't allow content to break outside
+ overflow: auto;
+}
+
+//
+// Figures
+//
+figure {
+ // Apply a consistent margin strategy (matches our type styles).
+ margin: 0 0 1em;
+}
+
+//
+// Images and content
+//
+
+img {
+ vertical-align: middle;
+ border-style: none; // remove the border on images inside links in IE 10-.
+}
+
+// Avoid 300ms click delay on touch devices that support the `touch-action` CSS property.
+//
+// In particular, unlike most other browsers, IE11+Edge on Windows 10 on touch devices and IE Mobile 10-11
+// DON'T remove the click delay when `` is present.
+// However, they DO support emoving the click delay via `touch-action: manipulation`.
+// See:
+// * https://getbootstrap.com/docs/4.0/content/reboot/#click-delay-optimization-for-touch
+// * http://caniuse.com/#feat=css-touch-action
+// * https://patrickhlauke.github.io/touch/tests/results/#suppressing-300ms-delay
+
+a,
+area,
+button,
+[role='button'],
+input:not([type='range']),
+label,
+select,
+summary,
+textarea {
+ touch-action: manipulation;
+}
+
+//
+// Tables
+//
+
+table {
+ border-collapse: collapse; // Prevent double borders
+}
+
+caption {
+ padding-top: 0.75em;
+ padding-bottom: 0.3em;
+ color: @text-color-secondary;
+ text-align: left;
+ caption-side: bottom;
+}
+
+//
+// Forms
+//
+
+input,
+button,
+select,
+optgroup,
+textarea {
+ margin: 0; // remove the margin in Firefox and Safari
+ color: inherit;
+ font-size: inherit;
+ font-family: inherit;
+ line-height: inherit;
+}
+
+button,
+input {
+ overflow: visible; // Show the overflow in Edge
+}
+
+button,
+select {
+ text-transform: none; // remove the inheritance of text transform in Firefox
+}
+
+// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
+// controls in Android 4.
+// 2. Correct the inability to style clickable types in iOS and Safari.
+button,
+@{html-selector} [type="button"], /* 1 */
+[type="reset"],
+[type="submit"] {
+ -webkit-appearance: button; // 2
+}
+
+// remove inner border and padding from Firefox, but don't restore the outline like Normalize.
+button::-moz-focus-inner,
+[type='button']::-moz-focus-inner,
+[type='reset']::-moz-focus-inner,
+[type='submit']::-moz-focus-inner {
+ padding: 0;
+ border-style: none;
+}
+
+input[type='radio'],
+input[type='checkbox'] {
+ box-sizing: border-box; // 1. Add the correct box sizing in IE 10-
+ padding: 0; // 2. remove the padding in IE 10-
+}
+
+input[type='date'],
+input[type='time'],
+input[type='datetime-local'],
+input[type='month'] {
+ // remove the default appearance of temporal inputs to avoid a Mobile Safari
+ // bug where setting a custom line-height prevents text from being vertically
+ // centered within the input.
+ // See https://bugs.webkit.org/show_bug.cgi?id=139848
+ // and https://github.com/twbs/bootstrap/issues/11266
+ -webkit-appearance: listbox;
+}
+
+textarea {
+ overflow: auto; // remove the default vertical scrollbar in IE.
+ // Textareas should really only resize vertically so they don't break their (horizontal) containers.
+ resize: vertical;
+}
+
+fieldset {
+ // Browsers set a default `min-width: min-content;` on fieldsets,
+ // unlike e.g. `