You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ma...@apache.org on 2025/03/01 00:55:48 UTC

(superset) branch template_less updated: simplifying

This is an automated email from the ASF dual-hosted git repository.

maximebeauchemin pushed a commit to branch template_less
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/template_less by this push:
     new a713bdf10f simplifying
a713bdf10f is described below

commit a713bdf10fdb14b302cce41cad9178db149504da
Author: Maxime Beauchemin <ma...@gmail.com>
AuthorDate: Fri Feb 28 16:54:05 2025 -0800

    simplifying
---
 .../packages/superset-ui-core/src/theme/Theme.tsx  | 250 ++++++++-------------
 .../packages/superset-ui-core/src/theme/index.tsx  |  14 +-
 .../packages/superset-ui-core/src/theme/types.ts   |  27 +++
 .../src/assets/stylesheets/antd/index.less         |  20 +-
 .../src/assets/stylesheets/less/variables.less     |  42 ++--
 superset-frontend/src/components/Tooltip/index.tsx |   6 +-
 .../{TextAreaControl.jsx => TextAreaControl.tsx}   |   8 +-
 superset-frontend/src/features/home/RightMenu.tsx  |   2 +-
 8 files changed, 165 insertions(+), 204 deletions(-)

diff --git a/superset-frontend/packages/superset-ui-core/src/theme/Theme.tsx b/superset-frontend/packages/superset-ui-core/src/theme/Theme.tsx
index 1a03c97794..70caee50ae 100644
--- a/superset-frontend/packages/superset-ui-core/src/theme/Theme.tsx
+++ b/superset-frontend/packages/superset-ui-core/src/theme/Theme.tsx
@@ -19,11 +19,7 @@
 /* eslint-disable react-prefer-function-component/react-prefer-function-component */
 // eslint-disable-next-line no-restricted-syntax
 import React from 'react';
-import {
-  theme as antdThemeImport,
-  ThemeConfig as AntdThemeConfig,
-  ConfigProvider,
-} from 'antd-v5';
+import { theme as antdThemeImport, ConfigProvider } from 'antd-v5';
 import tinycolor from 'tinycolor2';
 
 import {
@@ -31,21 +27,26 @@ import {
   CacheProvider as EmotionCacheProvider,
 } from '@emotion/react';
 import createCache from '@emotion/cache';
-// import { merge } from 'lodash';
 
 import {
-  AntdTokens,
+  AntdThemeConfig,
+  AnyThemeConfig,
+  SerializableThemeConfig,
   SupersetTheme,
   allowedAntdTokens,
   SharedAntdTokens,
-  SystemColors,
   ColorVariants,
-  DeprecatedColorVariations,
   DeprecatedThemeColors,
-  LegacySupersetTheme,
   FontSizeKey,
 } from './types';
 
+import {
+  normalizeThemeConfig,
+  serializeThemeConfig,
+  getSystemColors,
+  getDeprecatedColors,
+} from './utils';
+
 /* eslint-disable theme-colors/no-literal-colors */
 
 export class Theme {
@@ -84,111 +85,30 @@ export class Theme {
     xxl: 'fontSizeXXL',
   };
 
-  private constructor({
-    seed,
-    antdConfig,
-    isDark = false,
-  }: {
-    seed?: Partial<SupersetTheme>;
-    antdConfig?: AntdThemeConfig;
-    isDark?: boolean;
-  }) {
-    this.updateTheme = this.updateTheme.bind(this);
+  private constructor({ config }: { config?: AnyThemeConfig }) {
     this.SupersetThemeProvider = this.SupersetThemeProvider.bind(this);
 
-    if (seed && antdConfig) {
-      throw new Error('Pass either theme or antdConfig, not both.');
-    } else if (antdConfig) {
-      this.setThemeFromAntdConfig(antdConfig);
-    } else if (seed) {
-      this.setThemeFromSeed(seed || {}, isDark);
-    }
-  }
-
-  static fromSeed(seed?: Partial<SupersetTheme>, isDark = false): Theme {
-    const theme = new Theme({ seed, isDark });
-    return theme;
-  }
-
-  static fromAntdConfig(antdConfig: AntdThemeConfig): Theme {
-    const theme = new Theme({ antdConfig });
-    return theme;
-  }
-
-  private static genDeprecatedColorVariations(
-    color: string,
-    isDark: boolean,
-  ): DeprecatedColorVariations {
-    const bg = isDark ? '#FFF' : '#000';
-    const fg = isDark ? '#000' : '#FFF';
-    const adjustColor = (c: string, perc: number, tgt: string): string =>
-      tinycolor.mix(c, tgt, perc).toHexString();
-    return {
-      base: color,
-      light1: adjustColor(color, 20, fg),
-      light2: adjustColor(color, 45, fg),
-      light3: adjustColor(color, 70, fg),
-      light4: adjustColor(color, 90, fg),
-      light5: adjustColor(color, 95, fg),
-      dark1: adjustColor(color, 10, bg),
-      dark2: adjustColor(color, 20, bg),
-      dark3: adjustColor(color, 40, bg),
-      dark4: adjustColor(color, 60, bg),
-      dark5: adjustColor(color, 80, bg),
-    };
-  }
-
-  private static getColors(
-    systemColors: SystemColors,
-    isDark: boolean,
-  ): DeprecatedThemeColors {
-    /* This method provides a set of color variations based on the system colors.
-     * Goal is to deprecate usage of these in the future
-     */
-    const sc = systemColors;
-    return {
-      primary: Theme.genDeprecatedColorVariations(sc.colorPrimary, isDark),
-      error: Theme.genDeprecatedColorVariations(sc.colorError, isDark),
-      warning: Theme.genDeprecatedColorVariations(sc.colorWarning, isDark),
-      success: Theme.genDeprecatedColorVariations(sc.colorSuccess, isDark),
-      info: Theme.genDeprecatedColorVariations(sc.colorInfo, isDark),
-      grayscale: Theme.genDeprecatedColorVariations('#666', isDark),
-    };
-  }
+    // Create a new config object with default tokens
+    const newConfig: AnyThemeConfig = config ? { ...config } : {};
 
-  private static augmentSeedWithDefaults(
-    seed: Partial<SupersetTheme>,
-  ): Partial<SupersetTheme> {
-    return {
+    // Ensure token property exists with defaults
+    newConfig.token = {
       ...Theme.defaultTokens,
-      ...seed,
+      ...(config?.token || {}),
     };
-  }
 
-  private static getSystemColors(antdTokens: SharedAntdTokens): SystemColors {
-    return {
-      colorPrimary: antdTokens.colorPrimary,
-      colorError: antdTokens.colorError,
-      colorWarning: antdTokens.colorWarning,
-      colorSuccess: antdTokens.colorSuccess,
-      colorInfo: antdTokens.colorInfo,
-    };
+    this.setConfig(newConfig);
   }
 
-  private static getSupersetTheme(
-    seed: Partial<SupersetTheme>,
-    isDark = false,
-  ): SupersetTheme {
-    const antdConfig = Theme.getAntdConfig(seed, isDark);
-    const antdTokens = Theme.getFilteredAntdTheme(antdConfig);
-    const systemColors = Theme.getSystemColors(antdTokens);
-
-    const theme: SupersetTheme = {
-      colors: Theme.getColors(systemColors, isDark),
-      ...Theme.defaultTokens,
-      ...antdTokens,
-    };
-    return theme;
+  /**
+   * Create a theme from any theme configuration
+   * Automatically handles both AntdThemeConfig and SerializableThemeConfig
+   * If simple tokens are provided as { token: {...} }, they will be applied with defaults
+   * If no config is provided, uses default tokens
+   * Dark mode can be set via the algorithm property in the config
+   */
+  static fromConfig(config?: AnyThemeConfig): Theme {
+    return new Theme({ config });
   }
 
   private static getFilteredAntdTheme(
@@ -202,29 +122,45 @@ export class Theme {
     ) as SharedAntdTokens;
   }
 
-  private static getAntdConfig(
-    seed: Partial<SupersetTheme>,
-    isDark: boolean,
-  ): AntdThemeConfig {
-    const algorithm = isDark
-      ? antdThemeImport.darkAlgorithm
-      : antdThemeImport.defaultAlgorithm;
-    return {
-      token: seed,
-      algorithm,
-    };
+  private static getAntdTokens(
+    antdConfig: AntdThemeConfig,
+  ): Record<string, any> {
+    return antdThemeImport.getDesignToken(antdConfig);
   }
 
-  mergeTheme(partialTheme: Partial<LegacySupersetTheme>): void {
-    // const mergedTheme = merge({}, this.theme, partialTheme);
-    // const isDark = tinycolor(mergedTheme.colorBgBase).isDark();
-    // const antdConfig = Theme.getAntdConfig(systemColors, isDark);
-    // this.updateTheme(mergedTheme, antdConfig, isDark);
-  }
+  /**
+   * Update the theme using any theme configuration
+   * Automatically handles both AntdThemeConfig and SerializableThemeConfig
+   * Dark mode should be specified via the algorithm property in the config
+   */
+  setConfig(config: AnyThemeConfig): void {
+    const antdConfig = normalizeThemeConfig(config);
 
-  private updateTheme(theme: SupersetTheme, antdConfig: AntdThemeConfig): void {
-    this.theme = theme;
+    // Apply default tokens to token property
+    antdConfig.token = {
+      ...Theme.defaultTokens,
+      ...(antdConfig.token || {}),
+    };
+
+    // First phase: Let Ant Design compute the tokens
+    const tokens = Theme.getFilteredAntdTheme(antdConfig);
+
+    // Set the base theme properties
     this.antdConfig = antdConfig;
+    this.theme = {
+      ...Theme.defaultTokens,
+      ...antdConfig.token, // Passing through the extra, superset-specific tokens
+      ...tokens,
+      colors: {} as DeprecatedThemeColors, // Placeholder that will be filled in the second phase
+    };
+
+    // Second phase: Now that theme is initialized, we can determine if it's dark
+    // and generate the legacy colors correctly
+    const systemColors = getSystemColors(tokens);
+    const isDark = this.isThemeDark(); // Now we can safely call this
+    this.theme.colors = getDeprecatedColors(systemColors, isDark);
+
+    // Update the providers with the fully formed theme
     this.updateProviders(
       this.theme,
       this.antdConfig,
@@ -232,6 +168,13 @@ export class Theme {
     );
   }
 
+  /**
+   * Export the current theme as a serializable configuration
+   */
+  toSerializedConfig(): SerializableThemeConfig {
+    return serializeThemeConfig(this.antdConfig);
+  }
+
   private getToken(token: string): any {
     return (this.theme as Record<string, any>)[token];
   }
@@ -241,37 +184,40 @@ export class Theme {
     return this.getToken(fontSizeKey) || this.getToken('fontSize');
   }
 
-  private static getAntdTokens(antdConfig: AntdThemeConfig): AntdTokens {
-    return antdThemeImport.getDesignToken(antdConfig);
-  }
-
-  private isThemeDark(): boolean {
+  /**
+   * Check if the current theme is dark based on background color
+   */
+  isThemeDark(): boolean {
     return tinycolor(this.theme.colorBgContainer).isDark();
   }
 
-  setThemeFromSeed(seed: Partial<SupersetTheme>, isDark: boolean): void {
-    const augmentedSeed = Theme.augmentSeedWithDefaults(seed);
-    const theme = Theme.getSupersetTheme(augmentedSeed, isDark);
-    const antdConfig = Theme.getAntdConfig(augmentedSeed, isDark);
-    this.updateTheme(theme, antdConfig);
-  }
+  toggleDarkMode(isDark: boolean): void {
+    // Create a new config based on the current one
+    const newConfig = { ...this.antdConfig };
 
-  setThemeFromAntdConfig(antdConfig: AntdThemeConfig): void {
-    this.antdConfig = antdConfig;
-    const tokens = Theme.getFilteredAntdTheme(antdConfig);
-    const systemColors = Theme.getSystemColors(tokens);
-    const isDark = this.isThemeDark();
+    // Determine the new algorithm based on isDark
+    const newAlgorithm = isDark
+      ? antdThemeImport.darkAlgorithm
+      : antdThemeImport.defaultAlgorithm;
 
-    this.theme = {
-      colors: Theme.getColors(systemColors, isDark),
-      ...Theme.defaultTokens,
-      ...tokens,
-    };
-    this.updateProviders(
-      this.theme,
-      this.antdConfig,
-      createCache({ key: 'superset' }),
-    );
+    // Handle the case where algorithm is an array
+    if (Array.isArray(newConfig.algorithm)) {
+      // Filter out any existing dark/default algorithms
+      const otherAlgorithms = newConfig.algorithm.filter(
+        alg =>
+          alg !== antdThemeImport.darkAlgorithm &&
+          alg !== antdThemeImport.defaultAlgorithm,
+      );
+
+      // Add the new algorithm to the front of the array
+      newConfig.algorithm = [newAlgorithm, ...otherAlgorithms];
+    } else {
+      // Simple case: just replace the algorithm
+      newConfig.algorithm = newAlgorithm;
+    }
+
+    // Update the theme with the new configuration
+    this.setConfig(newConfig);
   }
 
   getColorVariants(color: string): ColorVariants {
diff --git a/superset-frontend/packages/superset-ui-core/src/theme/index.tsx b/superset-frontend/packages/superset-ui-core/src/theme/index.tsx
index 6bc1439b8e..56fccafb55 100644
--- a/superset-frontend/packages/superset-ui-core/src/theme/index.tsx
+++ b/superset-frontend/packages/superset-ui-core/src/theme/index.tsx
@@ -51,19 +51,7 @@ export function useTheme() {
 const styled = emotionStyled;
 
 // launching in in dark mode for now while iterating
-const themeObject = Theme.fromSeed({}, false);
-/*
-const themeObject = Theme.fromSeed({
-  token: {
-    colorPrimary: '#20a7c9',
-    colorError: '#e04355',
-    colorWarning: '#fcc700',
-    colorSuccess: '#5ac189',
-    colorInfo: '#66bcfe',
-  },
-  algorithm: antdThemeImport.defaultAlgorithm,
-});
- */
+const themeObject = Theme.fromConfig({});
 
 const { theme } = themeObject;
 const supersetTheme = theme;
diff --git a/superset-frontend/packages/superset-ui-core/src/theme/types.ts b/superset-frontend/packages/superset-ui-core/src/theme/types.ts
index 499b90bd9b..5fe97e664d 100644
--- a/superset-frontend/packages/superset-ui-core/src/theme/types.ts
+++ b/superset-frontend/packages/superset-ui-core/src/theme/types.ts
@@ -20,11 +20,38 @@
 // eslint-disable-next-line no-restricted-syntax
 import { theme as antdThemeImport } from 'antd-v5';
 
+/**
+ * Get AntdThemeConfig type from the theme object
+ */
+import type { ThemeConfig } from 'antd-v5';
+
 /**
  * Grab all antd tokens via getDesignToken(...).
  * (Same as in the original file.)
  */
 export type AntdTokens = ReturnType<typeof antdThemeImport.getDesignToken>;
+export type AntdThemeConfig = ThemeConfig;
+
+/**
+ * A serializable version of Ant Design's ThemeConfig
+ * Compatible with theme editor exports
+ */
+export type SerializableThemeConfig = {
+  token?: Record<string, any>;
+  components?: Record<string, any>;
+  algorithm?:
+    | 'default'
+    | 'dark'
+    | 'compact'
+    | ('default' | 'dark' | 'compact')[];
+  hashed?: boolean;
+  inherit?: boolean;
+};
+
+/**
+ * A combined type that can be either a regular AntdThemeConfig or a SerializableThemeConfig
+ */
+export type AnyThemeConfig = AntdThemeConfig | SerializableThemeConfig;
 
 /** Minimal color system references. */
 export type FontSizeKey = 'xs' | 's' | 'm' | 'l' | 'xl' | 'xxl';
diff --git a/superset-frontend/src/assets/stylesheets/antd/index.less b/superset-frontend/src/assets/stylesheets/antd/index.less
index cc97a40751..ae9f0c1e6e 100644
--- a/superset-frontend/src/assets/stylesheets/antd/index.less
+++ b/superset-frontend/src/assets/stylesheets/antd/index.less
@@ -35,7 +35,7 @@
   Theme variables here: https://github.com/ant-design/ant-design/blob/master/components/style/themes/default.less
 */
 /* Core Colors */
-@primary-color: #20a7c9;
+@primary-color: #007aa0;
 @info-color: #66bcfe;
 @processing-color: #525252;
 @success-color: #5ac189;
@@ -44,17 +44,17 @@
 @normal-color: #d1d1d1;
 
 // Menu-related
-@menu-highlight-color: #20a7c9;
+@menu-highlight-color: #007aa0;
 @menu-item-active-bg: ;
-@menu-item-color: #136479;
+@menu-item-color: #004960;
 @menu-popup-bg: #ffffff;
 @menu-bg: #ffffff;
 
 @tabs-card-head-background: #ffffff;
 @component-background: #ffffff;
-@select-item-selected-bg: #f0feff;
-@select-item-active-bg: #f0feff;
-@select-item-hover-bg: #f0feff;
+@select-item-selected-bg: #cadfe0;
+@select-item-active-bg: #cadfe0;
+@select-item-hover-bg: #cadfe0;
 
 @item-hover-bg: #ffffff;
 @menu-item-hover-bg: #ffffff;
@@ -87,7 +87,7 @@
 @border-radius-lg: 8;
 
 /* Buttons */
-@btn-primary-bg: #20a7c9;
+@btn-primary-bg: #007aa0;
 @btn-default-bg: #ffffff;
 @btn-default-border: #d9d9d9;
 @btn-danger-bg: #e04355;
@@ -96,7 +96,7 @@
 /* Inputs */
 //@input-bg: ;
 @input-border-color: #d9d9d9;
-@input-hover-border-color: #6dd3e3;
+@input-hover-border-color: #3ca5ba;
 
 /* Menus */
 @menu-bg: #ffffff;
@@ -105,7 +105,7 @@
 @menu-inline-submenu-bg: #ffffff;
 @menu-highlight-color: rgba(0,0,0,0.88);
 @menu-highlight-danger-color: #e04355;
-@menu-item-active-bg: #20a7c9;
+@menu-item-active-bg: #007aa0;
 @menu-item-active-danger-bg: #fff0f0;
 @menu-item-group-title-color: rgba(0,0,0,0.88);
 
@@ -122,7 +122,7 @@
 /* Tables */
 @table-header-bg: #ffffff;
 @table-row-hover-bg: #ffffff;
-@table-selected-row-bg: #f0feff;
+@table-selected-row-bg: #cadfe0;
 
 /* Motion */
 @motion-duration-fast: 0.1s;
diff --git a/superset-frontend/src/assets/stylesheets/less/variables.less b/superset-frontend/src/assets/stylesheets/less/variables.less
index 5fc8086b6b..4423211c56 100644
--- a/superset-frontend/src/assets/stylesheets/less/variables.less
+++ b/superset-frontend/src/assets/stylesheets/less/variables.less
@@ -21,33 +21,33 @@
 /* COLORS                                                               */
 /************************************************************************/
 
-@primary-color: #20a7c9;
+@primary-color: #007aa0;
 @indicator-color: @primary-color;
 
-@brand-primary-dark1: #20a7c9;
-@brand-primary-dark2: #1a86a1;
-@brand-primary-light1: #4db9d4;
-@brand-primary-light2: #84cfe1;
-@brand-primary-light3: #bce5ef;
-@brand-primary-light4: #e9f6fa;
-@brand-primary-light5: #f4fbfc;
-
-@brand-secondary: #20a7c9;
-@brand-secondary-dark1: #20a7c9;
-@brand-secondary-dark2: #1a86a1;
-@brand-secondary-dark3: #136479;
-@brand-secondary-light1: #4db9d4;
-@brand-secondary-light2: #84cfe1;
-@brand-secondary-light3: #bce5ef;
-@brand-secondary-light4: #e9f6fa;
-@brand-secondary-light5: #f4fbfc;
+@brand-primary-dark1: #007aa0;
+@brand-primary-dark2: #006280;
+@brand-primary-light1: #3395b3;
+@brand-primary-light2: #73b6cb;
+@brand-primary-light3: #b3d7e3;
+@brand-primary-light4: #e6f2f6;
+@brand-primary-light5: #f2f8fa;
+
+@brand-secondary: #007aa0;
+@brand-secondary-dark1: #007aa0;
+@brand-secondary-dark2: #006280;
+@brand-secondary-dark3: #004960;
+@brand-secondary-light1: #3395b3;
+@brand-secondary-light2: #73b6cb;
+@brand-secondary-light3: #b3d7e3;
+@brand-secondary-light4: #e6f2f6;
+@brand-secondary-light5: #f2f8fa;
 
 // TODO line up with theme
 @almost-black: #141414;
 @gray-dark: #3d3d3d;
 @gray-light: #f0f0f0;
 @gray-light5: #f7f7f7;
-@gray: #20a7c9;
+@gray: #007aa0;
 @gray-bg: #f0f0f0;
 @gray-heading: rgba(0,0,0,0.88);
 @menu-hover: rgba(0,0,0,0.88);
@@ -59,8 +59,8 @@
 /**************************** text-specific *****************************/
 @text-color: #000;
 @heading-color: #000;
-@link: #20a7c9;
-@link-hover: #1a86a1;
+@link: #007aa0;
+@link-hover: #006280;
 
 /***************************** status colors ****************************/
 @info: #66bcfe;
diff --git a/superset-frontend/src/components/Tooltip/index.tsx b/superset-frontend/src/components/Tooltip/index.tsx
index 615ad802e7..528bfc475b 100644
--- a/superset-frontend/src/components/Tooltip/index.tsx
+++ b/superset-frontend/src/components/Tooltip/index.tsx
@@ -18,9 +18,11 @@
  */
 import { supersetTheme } from '@superset-ui/core';
 import { Tooltip as AntdTooltip } from 'antd-v5';
-import { TooltipProps, TooltipPlacement } from 'antd-v5/lib/tooltip';
+import type { TooltipProps } from 'antd-v5';
 
-export { TooltipProps, TooltipPlacement };
+// Re-export the types
+export type { TooltipProps };
+export type { TooltipPlacement } from 'antd-v5';
 
 export const Tooltip = ({ overlayStyle, ...props }: TooltipProps) => (
   <AntdTooltip
diff --git a/superset-frontend/src/explore/components/controls/TextAreaControl.jsx b/superset-frontend/src/explore/components/controls/TextAreaControl.tsx
similarity index 95%
rename from superset-frontend/src/explore/components/controls/TextAreaControl.jsx
rename to superset-frontend/src/explore/components/controls/TextAreaControl.tsx
index e8f165c8e1..9f8200c8e5 100644
--- a/superset-frontend/src/explore/components/controls/TextAreaControl.jsx
+++ b/superset-frontend/src/explore/components/controls/TextAreaControl.tsx
@@ -19,10 +19,8 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
 import { TextArea } from 'src/components/Input';
-import {
-  Tooltip,
-  TooltipProps as TooltipOptions,
-} from 'src/components/Tooltip';
+import { Tooltip } from 'src/components/Tooltip';
+import type { TooltipProps } from 'antd-v5'; // Import directly from antd-v5
 import { t, withTheme } from '@superset-ui/core';
 
 import Button from 'src/components/Button';
@@ -59,7 +57,7 @@ const propTypes = {
     'vertical',
   ]),
   textAreaStyles: PropTypes.object,
-  tooltipOptions: PropTypes.oneOf([null, TooltipOptions]),
+  tooltipOptions: PropTypes.object, // Changed from PropTypes.oneOf to PropTypes.object
 };
 
 const defaultProps = {
diff --git a/superset-frontend/src/features/home/RightMenu.tsx b/superset-frontend/src/features/home/RightMenu.tsx
index 4aac551601..3c496c2776 100644
--- a/superset-frontend/src/features/home/RightMenu.tsx
+++ b/superset-frontend/src/features/home/RightMenu.tsx
@@ -482,7 +482,7 @@ const RightMenu = ({
           <span>
             <Switch
               onChange={(checked: boolean) => {
-                themeObject.setThemeFromSeed({}, checked);
+                themeObject.toggleDarkMode(checked);
               }}
             />
           </span>