korbit-ai[bot] commented on code in PR #35220:
URL: https://github.com/apache/superset/pull/35220#discussion_r2365266359
##########
superset-frontend/src/theme/ThemeController.ts:
##########
@@ -589,48 +669,81 @@ export class ThemeController {
*/
private getThemeForMode(mode: ThemeMode): AnyThemeConfig | null {
// Priority 1: Dev theme override (highest priority for development)
- // Dev overrides affect all contexts
+ // Dev overrides affect all contexts but still merge with base
if (this.devThemeOverride) {
- return this.devThemeOverride;
+ const normalizedOverride = this.normalizeTheme(this.devThemeOverride);
+ const isDarkMode = this.isThemeDark(normalizedOverride);
+ const baseTheme = isDarkMode ? this.baseThemeDark :
this.baseThemeDefault;
+
+ if (baseTheme) {
+ const mergedTheme = Theme.fromConfig(normalizedOverride, baseTheme);
+ return mergedTheme.toSerializedConfig();
+ }
+ return normalizedOverride;
}
// Priority 2: System theme based on mode (applies to all contexts)
let resolvedMode: ThemeMode = mode;
if (mode === ThemeMode.SYSTEM) {
- // OS preference is allowed when dark theme exists
- if (this.darkTheme === null) return null;
+ // OS preference is allowed when dark theme exists or base dark theme
exists
+ if (this.darkTheme === null && this.baseThemeDark === null) return null;
resolvedMode = ThemeController.getSystemPreferredMode();
}
- if (!this.hasCustomThemes) {
- const baseTheme = this.defaultTheme.token as Partial<SupersetTheme>;
- return getAntdConfig(baseTheme, resolvedMode === ThemeMode.DARK);
+ // Get the appropriate base theme for the mode
+ let baseTheme: AnyThemeConfig | null = null;
+ let customTheme: AnyThemeConfig | null = null;
+
+ if (resolvedMode === ThemeMode.DARK) {
+ baseTheme = this.baseThemeDark || this.baseThemeDefault;
+ customTheme = this.darkTheme;
+ } else {
+ baseTheme = this.baseThemeDefault;
+ customTheme = this.defaultTheme;
+ }
Review Comment:
### Asymmetric base theme fallback logic <sub></sub>
<details>
<summary>Tell me more</summary>
###### What is the issue?
Dark mode fallback logic uses default base theme when base dark theme is
missing, but light mode doesn't have equivalent fallback to base dark theme.
###### Why this matters
This asymmetric fallback behavior could cause inconsistent theming where
dark mode gets a fallback but light mode doesn't, potentially leading to broken
themes in edge cases.
###### Suggested change ∙ *Feature Preview*
Make the fallback logic symmetric:
```typescript
if (resolvedMode === ThemeMode.DARK) {
baseTheme = this.baseThemeDark || this.baseThemeDefault;
customTheme = this.darkTheme;
} else {
baseTheme = this.baseThemeDefault || this.baseThemeDark;
customTheme = this.defaultTheme;
}
```
###### Provide feedback to improve future suggestions
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/e2cb8608-838a-476d-8da9-2de476700db2/upvote)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/e2cb8608-838a-476d-8da9-2de476700db2?what_not_true=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/e2cb8608-838a-476d-8da9-2de476700db2?what_out_of_scope=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/e2cb8608-838a-476d-8da9-2de476700db2?what_not_in_standard=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/e2cb8608-838a-476d-8da9-2de476700db2)
</details>
<sub>
💬 Looking for more details? Reply to this comment to chat with Korbit.
</sub>
<!--- korbi internal id:1c932f49-a25b-4088-a4b3-dc942c71ba1a -->
[](1c932f49-a25b-4088-a4b3-dc942c71ba1a)
##########
superset/views/base.py:
##########
@@ -348,34 +350,74 @@ def get_theme_bootstrap_data() -> dict[str, Any]:
"Invalid JSON in system dark theme %s", dark_theme_model.id
)
# Fallback to config
- dark_theme = get_config_value("THEME_DARK")
+ dark_theme = config_theme_dark
else:
# No system dark theme in database, use config
- dark_theme = get_config_value("THEME_DARK")
+ dark_theme = config_theme_dark
else:
- # UI theme administration disabled, use config-based themes
- default_theme = get_config_value("THEME_DEFAULT")
- dark_theme = get_config_value("THEME_DARK")
-
- # Validate theme configurations
- if not is_valid_theme(default_theme):
+ # UI theme administration disabled
+ # Use config-based themes
+ default_theme = config_theme_default
+ dark_theme = config_theme_dark
+
+ # Get base themes from config (with fallback for backwards compatibility)
+ base_theme = app.config.get("BASE_THEME_DEFAULT", None)
+ base_theme_dark = app.config.get("BASE_THEME_DARK", None)
+
+ # Determine if themes need to fall back to base themes
+ # A theme needs fallback if it's None or empty
+ def should_use_base(theme):
+ """Check if a theme should be replaced with base theme entirely"""
+ if theme is None or theme == {}:
+ return True
+
+ return False
+
+ # Handle default theme fallback
+ if should_use_base(default_theme):
+ # When config theme is None, don't provide a custom theme
+ # The frontend will use base theme only
+ default_theme = {}
+ elif not is_valid_theme(default_theme):
logger.warning(
- "Invalid default theme configuration: %s, using empty theme",
+ "Invalid default theme configuration: %s, clearing it",
default_theme,
)
default_theme = {}
- if not is_valid_theme(dark_theme):
+ # Handle dark theme fallback
+ if should_use_base(dark_theme):
+ # When config theme is None, don't provide a custom theme
+ # The frontend will use base dark theme only
+ dark_theme = {}
+ elif not is_valid_theme(dark_theme):
logger.warning(
- "Invalid dark theme configuration: %s, using empty theme",
+ "Invalid dark theme configuration: %s, clearing it",
dark_theme,
)
dark_theme = {}
+ # Validate base theme configurations
+ if base_theme is not None and not is_valid_theme(base_theme):
+ logger.warning(
+ "Invalid base theme configuration: %s, ignoring",
+ base_theme,
+ )
+ base_theme = None
+
+ if base_theme_dark is not None and not is_valid_theme(base_theme_dark):
+ logger.warning(
+ "Invalid base dark theme configuration: %s, ignoring",
+ base_theme_dark,
+ )
+ base_theme_dark = None
Review Comment:
### Duplicated validation logic <sub></sub>
<details>
<summary>Tell me more</summary>
###### What is the issue?
Duplicate validation logic for base themes that could be consolidated into a
reusable pattern.
###### Why this matters
The same validation pattern is repeated for both base themes, leading to
code duplication and potential maintenance overhead. While not a major
performance issue, it represents inefficient code organization.
###### Suggested change ∙ *Feature Preview*
Create a helper function or use a loop to validate both themes:
```python
for theme_name, theme_var in [("base theme", base_theme), ("base dark
theme", base_theme_dark)]:
if theme_var is not None and not is_valid_theme(theme_var):
logger.warning("Invalid %s configuration: %s, ignoring", theme_name,
theme_var)
if theme_name == "base theme":
base_theme = None
else:
base_theme_dark = None
```
###### Provide feedback to improve future suggestions
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/f3663fbe-aa8d-401d-8140-9f89dee54ab8/upvote)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/f3663fbe-aa8d-401d-8140-9f89dee54ab8?what_not_true=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/f3663fbe-aa8d-401d-8140-9f89dee54ab8?what_out_of_scope=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/f3663fbe-aa8d-401d-8140-9f89dee54ab8?what_not_in_standard=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/f3663fbe-aa8d-401d-8140-9f89dee54ab8)
</details>
<sub>
💬 Looking for more details? Reply to this comment to chat with Korbit.
</sub>
<!--- korbi internal id:f0d51401-d22c-4d54-8a25-0fe2f6fe52f8 -->
[](f0d51401-d22c-4d54-8a25-0fe2f6fe52f8)
##########
superset-frontend/packages/superset-ui-core/src/theme/Theme.tsx:
##########
@@ -118,9 +53,48 @@ export class Theme {
* 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
+ * @param config - The theme configuration
+ * @param baseTheme - Optional base theme to apply under the config
*/
- static fromConfig(config?: AnyThemeConfig): Theme {
- return new Theme({ config });
+ static fromConfig(
+ config?: AnyThemeConfig,
+ baseTheme?: AnyThemeConfig,
+ ): Theme {
+ let mergedConfig: AnyThemeConfig | undefined = config;
+
+ if (baseTheme && config) {
+ mergedConfig = {
+ ...baseTheme,
+ ...config,
+ } as AnyThemeConfig;
+
+ if (baseTheme.token || config.token) {
+ (mergedConfig as any).token = {
+ ...(baseTheme.token || {}),
+ ...(config.token || {}),
+ };
+ }
Review Comment:
### Complex Theme Merging Logic <sub></sub>
<details>
<summary>Tell me more</summary>
###### What is the issue?
The theme merging logic in fromConfig is complex and uses type assertions,
making it difficult to maintain and type-unsafe.
###### Why this matters
Complex merging logic embedded in the static factory method makes the code
harder to test, maintain, and increases the likelihood of bugs when handling
theme configurations.
###### Suggested change ∙ *Feature Preview*
```typescript
private static mergeThemeConfigs(base?: AnyThemeConfig, override?:
AnyThemeConfig): AnyThemeConfig {
if (!base) return override || {};
if (!override) return base;
return {
...base,
...override,
token: {
...(base.token || {}),
...(override.token || {})
},
components: this.mergeComponents(base.components,
override.components)
};
}
static fromConfig(config?: AnyThemeConfig, baseTheme?: AnyThemeConfig):
Theme {
const mergedConfig = this.mergeThemeConfigs(baseTheme, config);
return new Theme({ config: mergedConfig });
}
```
###### Provide feedback to improve future suggestions
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/3dc4bef7-7b88-40d8-a654-281d6fd779fb/upvote)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/3dc4bef7-7b88-40d8-a654-281d6fd779fb?what_not_true=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/3dc4bef7-7b88-40d8-a654-281d6fd779fb?what_out_of_scope=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/3dc4bef7-7b88-40d8-a654-281d6fd779fb?what_not_in_standard=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/3dc4bef7-7b88-40d8-a654-281d6fd779fb)
</details>
<sub>
💬 Looking for more details? Reply to this comment to chat with Korbit.
</sub>
<!--- korbi internal id:b26beb71-3e06-4bea-9042-f62aaad443d8 -->
[](b26beb71-3e06-4bea-9042-f62aaad443d8)
##########
superset-frontend/packages/superset-ui-core/src/theme/GlobalStyles.tsx:
##########
@@ -16,6 +16,18 @@
* specific language governing permissions and limitations
* under the License.
*/
+
+// @fontsource/* v5.1+ doesn't play nice with eslint-import plugin v2.31+
+/* eslint-disable import/extensions */
+import '@fontsource/inter/200.css';
+import '@fontsource/inter/400.css';
+import '@fontsource/inter/500.css';
+import '@fontsource/inter/600.css';
+import '@fontsource/fira-code/400.css';
+import '@fontsource/fira-code/500.css';
+import '@fontsource/fira-code/600.css';
Review Comment:
### Blocking font CSS imports delay rendering <sub></sub>
<details>
<summary>Tell me more</summary>
###### What is the issue?
Multiple individual CSS font imports are loaded synchronously at module
level, causing blocking network requests during initial bundle parsing.
###### Why this matters
This creates a waterfall of blocking CSS requests that delay the critical
rendering path and increase Time to First Contentful Paint, especially on
slower networks.
###### Suggested change ∙ *Feature Preview*
Use dynamic imports with `import()` to load fonts asynchronously, or combine
font weights into fewer CSS files, or use font-display: swap in the CSS to
prevent render blocking:
```typescript
// Load fonts asynchronously
const loadFonts = async () => {
await Promise.all([
import('@fontsource/inter/200.css'),
import('@fontsource/inter/400.css'),
import('@fontsource/inter/500.css'),
import('@fontsource/inter/600.css'),
import('@fontsource/fira-code/400.css'),
import('@fontsource/fira-code/500.css'),
import('@fontsource/fira-code/600.css')
]);
};
// Call in useEffect or during app initialization
```
###### Provide feedback to improve future suggestions
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/f46cf04e-2239-425e-9a75-80f41a77f287/upvote)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/f46cf04e-2239-425e-9a75-80f41a77f287?what_not_true=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/f46cf04e-2239-425e-9a75-80f41a77f287?what_out_of_scope=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/f46cf04e-2239-425e-9a75-80f41a77f287?what_not_in_standard=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/f46cf04e-2239-425e-9a75-80f41a77f287)
</details>
<sub>
💬 Looking for more details? Reply to this comment to chat with Korbit.
</sub>
<!--- korbi internal id:8017a30a-b561-4290-9ee9-aebb7412c367 -->
[](8017a30a-b561-4290-9ee9-aebb7412c367)
##########
superset-frontend/src/theme/ThemeController.ts:
##########
@@ -589,48 +669,81 @@ export class ThemeController {
*/
private getThemeForMode(mode: ThemeMode): AnyThemeConfig | null {
// Priority 1: Dev theme override (highest priority for development)
- // Dev overrides affect all contexts
+ // Dev overrides affect all contexts but still merge with base
if (this.devThemeOverride) {
- return this.devThemeOverride;
+ const normalizedOverride = this.normalizeTheme(this.devThemeOverride);
+ const isDarkMode = this.isThemeDark(normalizedOverride);
+ const baseTheme = isDarkMode ? this.baseThemeDark :
this.baseThemeDefault;
+
+ if (baseTheme) {
+ const mergedTheme = Theme.fromConfig(normalizedOverride, baseTheme);
+ return mergedTheme.toSerializedConfig();
+ }
+ return normalizedOverride;
}
// Priority 2: System theme based on mode (applies to all contexts)
let resolvedMode: ThemeMode = mode;
if (mode === ThemeMode.SYSTEM) {
- // OS preference is allowed when dark theme exists
- if (this.darkTheme === null) return null;
+ // OS preference is allowed when dark theme exists or base dark theme
exists
+ if (this.darkTheme === null && this.baseThemeDark === null) return null;
resolvedMode = ThemeController.getSystemPreferredMode();
}
- if (!this.hasCustomThemes) {
- const baseTheme = this.defaultTheme.token as Partial<SupersetTheme>;
- return getAntdConfig(baseTheme, resolvedMode === ThemeMode.DARK);
+ // Get the appropriate base theme for the mode
+ let baseTheme: AnyThemeConfig | null = null;
+ let customTheme: AnyThemeConfig | null = null;
Review Comment:
### Complex theme resolution logic needs strategy pattern <sub></sub>
<details>
<summary>Tell me more</summary>
###### What is the issue?
The getThemeForMode method is complex with multiple levels of theme
resolution logic and conditional branches, making it difficult to understand
and maintain.
###### Why this matters
Complex methods with multiple responsibilities and decision paths are prone
to bugs and make it harder to modify theme resolution logic in the future.
###### Suggested change ∙ *Feature Preview*
Implement a Strategy pattern for theme resolution:
```typescript
interface ThemeResolutionStrategy {
resolveTheme(mode: ThemeMode): AnyThemeConfig | null;
}
class DevOverrideStrategy implements ThemeResolutionStrategy { ... }
class SystemThemeStrategy implements ThemeResolutionStrategy { ... }
class BaseThemeStrategy implements ThemeResolutionStrategy { ... }
class ThemeResolver {
constructor(private strategies: ThemeResolutionStrategy[]) {}
resolve(mode: ThemeMode): AnyThemeConfig | null {
for (const strategy of this.strategies) {
const theme = strategy.resolveTheme(mode);
if (theme) return theme;
}
return null;
}
}
```
###### Provide feedback to improve future suggestions
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/d0791393-100d-4650-a13a-b11e6a4dd5e9/upvote)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/d0791393-100d-4650-a13a-b11e6a4dd5e9?what_not_true=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/d0791393-100d-4650-a13a-b11e6a4dd5e9?what_out_of_scope=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/d0791393-100d-4650-a13a-b11e6a4dd5e9?what_not_in_standard=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/d0791393-100d-4650-a13a-b11e6a4dd5e9)
</details>
<sub>
💬 Looking for more details? Reply to this comment to chat with Korbit.
</sub>
<!--- korbi internal id:284b60c0-6386-4b2d-9fd3-e4200dca818c -->
[](284b60c0-6386-4b2d-9fd3-e4200dca818c)
##########
superset/config.py:
##########
@@ -723,46 +723,88 @@ class D3TimeFormat(TypedDict, total=False):
# This is merely a default
EXTRA_CATEGORICAL_COLOR_SCHEMES: list[dict[str, Any]] = []
-# ---------------------------------------------------
-# Theme Configuration for Superset
-# ---------------------------------------------------
+# -----------------------------------------------------------------------------
+# Theme System Configuration
+# -----------------------------------------------------------------------------
# Superset supports custom theming through Ant Design's theme structure.
-# This allows users to customize colors, fonts, and other UI elements.
#
-# Theme Generation:
-# - Use the Ant Design theme editor: https://ant.design/theme-editor
-# - Export or copy the generated theme JSON and assign to the variables below
-# - For detailed instructions:
https://superset.apache.org/docs/configuration/theming/
+# Theme Hierarchy (layers apply in order, each overriding previous):
+# 1. BASE_THEME_DEFAULT/BASE_THEME_DARK - Foundation tokens ALWAYS present
+# 2. THEME_DEFAULT/THEME_DARK - Config themes (overlay on BASE themes)
+# 3. System CRUD themes (when ENABLE_UI_THEME_ADMINISTRATION=True) - Set via UI
+# 4. Dashboard CRUD themes - Applied locally per dashboard with bolt button
#
-# To expose a JSON theme editor modal that can be triggered from the navbar
-# set the `ENABLE_THEME_EDITOR` feature flag to True.
+# Theme Merging:
+# - Base themes are ALWAYS the foundation - never removed, only overridden
+# - Each layer only adds/modifies specific tokens, preserving all others
+# - Empty theme {} or None means "no custom tokens at this layer"
+# - All themes are merged: base + config overlays + system overlays +
dashboard overlays
#
-# Theme Structure:
-# Each theme should follow Ant Design's theme format.
-# To create custom themes, use the Ant Design Theme Editor at
https://ant.design/theme-editor
-# and copy the generated JSON configuration.
+# System Theme Behavior (UI Administration):
+# - Only themes explicitly marked as system (via moon/sun buttons) are used
+# - Removing a system theme falls back to config theme (or base if config is
None)
+# - No automatic fallback to other themes in the database
#
-# Example theme definition:
-# THEME_DEFAULT = {
-# "token": {
-# "colorPrimary": "#2893B3",
-# "colorSuccess": "#5ac189",
-# "colorWarning": "#fcc700",
-# "colorError": "#e04355",
-# "fontFamily": "'Inter', Helvetica, Arial",
-# ... # other tokens
-# },
-# ... # other theme properties
-# }
+# Theme Generation:
+# - Use the Ant Design theme editor: https://ant.design/theme-editor
+# - Export the generated JSON and assign to the theme variables
+# - To expose a JSON theme editor modal in the UI, set ENABLE_THEME_EDITOR
feature flag to True
+#
+# Example: If BASE_THEME_DEFAULT sets colorPrimary: "#2893B3" and a custom
theme sets
+# colorPrimary: "#FF0000", the final theme will have colorPrimary: "#FF0000"
+# -----------------------------------------------------------------------------
+
+# Base theme with Superset's default tokens (foundation for all themes)
+BASE_THEME_DEFAULT: Theme = {
+ "token": {
+ # Brand
+ "brandLogoAlt": "Apache Superset",
+ "brandLogoUrl": "/static/assets/images/superset-logo-horiz.png",
+ "brandLogoMargin": "18px",
+ "brandLogoHref": "/",
+ "brandLogoHeight": "24px",
+ # Spinner
+ "brandSpinnerUrl": None,
+ "brandSpinnerSvg": None,
+ # Default colors
+ "colorPrimary": "#2893B3", # NOTE: previous lighter primary color was
#20a7c9 # noqa: E501
+ "colorLink": "#2893B3",
+ "colorError": "#e04355",
+ "colorWarning": "#fcc700",
+ "colorSuccess": "#5ac189",
+ "colorInfo": "#66bcfe",
+ # Fonts
+ "fontFamily": "'Inter', Helvetica, Arial",
+ "fontFamilyCode": "'Fira Code', 'Courier New', monospace",
+ # Extra tokens
+ "transitionTiming": 0.3,
+ "brandIconMaxWidth": 37,
+ "fontSizeXS": "8",
+ "fontSizeXXL": "28",
+ "fontWeightNormal": "400",
+ "fontWeightLight": "300",
+ "fontWeightStrong": 500,
+ },
+ "algorithm": "default",
+}
+# Base dark theme configuration - foundation tokens for dark mode
+# Inherits all tokens from BASE_THEME_DEFAULT and adds dark algorithm
+# This ensures dark mode gets the correct algorithm even if THEME_DARK is empty
+BASE_THEME_DARK: Theme = {
+ **BASE_THEME_DEFAULT,
+ "algorithm": "dark",
+}
Review Comment:
### Shared mutable token dictionary between base themes <sub></sub>
<details>
<summary>Tell me more</summary>
###### What is the issue?
The BASE_THEME_DARK theme uses dictionary unpacking (**BASE_THEME_DEFAULT)
which creates a shallow copy, but then overwrites the 'algorithm' key. This
means both themes share the same nested 'token' dictionary object in memory.
###### Why this matters
When any code modifies the 'token' dictionary in either BASE_THEME_DEFAULT
or BASE_THEME_DARK, it will affect both themes simultaneously since they
reference the same object. This could lead to unexpected theme corruption where
changes to one theme accidentally modify the other.
###### Suggested change ∙ *Feature Preview*
Use deep copy to ensure each theme has its own independent token dictionary:
```python
import copy
BASE_THEME_DARK: Theme = {
**copy.deepcopy(BASE_THEME_DEFAULT),
"algorithm": "dark",
}
```
Alternatively, restructure to avoid the shared reference:
```python
_BASE_THEME_TOKENS = {
# Brand
"brandLogoAlt": "Apache Superset",
# ... all token definitions
}
BASE_THEME_DEFAULT: Theme = {
"token": _BASE_THEME_TOKENS.copy(),
"algorithm": "default",
}
BASE_THEME_DARK: Theme = {
"token": _BASE_THEME_TOKENS.copy(),
"algorithm": "dark",
}
```
###### Provide feedback to improve future suggestions
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/55ecfabe-e02f-41fd-b8b3-b420ece150c3/upvote)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/55ecfabe-e02f-41fd-b8b3-b420ece150c3?what_not_true=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/55ecfabe-e02f-41fd-b8b3-b420ece150c3?what_out_of_scope=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/55ecfabe-e02f-41fd-b8b3-b420ece150c3?what_not_in_standard=true)
[](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/55ecfabe-e02f-41fd-b8b3-b420ece150c3)
</details>
<sub>
💬 Looking for more details? Reply to this comment to chat with Korbit.
</sub>
<!--- korbi internal id:0809613f-4a86-4b6c-9570-b98ad150d5b3 -->
[](0809613f-4a86-4b6c-9570-b98ad150d5b3)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]