mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-25 20:54:18 +00:00
Dark theme for Explorer (#2185)
* First dark theme commits for command bar * Updated theme on sidebar * Updated tabs, sidebar, splash screen * settings theme changes * Dark theme applied to Monaco editor * Dark theme to stored procedures * Fixed sidebar scroll * Updated scroll issue in sidebar * Command bar items fixed * Fixed lint errors * fixed lint errors * settings side panel fixed * Second last iteration for css * Fixed all the issues of css * Updated the theme icon for now on DE to change the theme from portal/DE itself * Formatting issue resolved * Remove CloudShellTerminalComponent changes - revert to master version * Fixed test issue * Fixed formatting issue * Fix tests: update snapshots and revert xterm imports for compatibility * Fix xterm imports in CloudShellTerminalComponent to use @xterm packages * Fix Cloud Shell component imports for compatibility * Update test snapshots * Fix xterm package consistency across all CloudShell components * Fix TypeScript compilation errors in CloudShell components and query Documents - Standardized xterm package imports across CloudShell components to use legacy 'xterm' package - Fixed Terminal type compatibility issues in CommonUtils.tsx - Added type casting for enableQueryControl property in queryDocuments.ts to handle Azure Cosmos SDK interface limitations - Applied code formatting to ensure consistency * Update failing snapshot tests - Updated TreeNodeComponent snapshot tests for loading states - Updated ThroughputInputAutoPilotV3Component snapshots for number formatting changes (10,00,000 -> 1,000,000) - All snapshot tests now pass * Fixed test issue * Fixed test issue * Updated the buttons for theme * Updated the Theme changes based on portal theme changes * Updated review comments * Updated the duplicate code and fixed the fabric react error * Few places styling added and resolving few comments * Fixed errors * Fixed comments * Fixed comments * Fixed comments * Fixed full text policy issue for mongoru accounts * Resolved comments for class Name and few others * Added css for homepage in ru accounts * Final commit with all the feedback issues resolved * Lint error resolved * Updated the review comments and few Ui issues * Resolved review comments and changed header bg and active state color * Moved svg code to different file and imported * css fixed for the hpome page boxed for ru account * Lint errors * Fixed boxes issue in ru accounts * Handled the initial theme from the portal * Updated snap * Update snapshots for TreeNodeComponent and CreateCopyJobScreensProvider tests * Fix duplicate DataExplorerRoot test id causing Playwright strict mode violation * Fix locale-dependent number formatting in ThroughputInputAutoPilotV3Component --------- Co-authored-by: Sakshi Gupta <sakshig+microsoft@microsoft.com> Co-authored-by: Sakshi Gupta <sakshig@microsoft.com>
This commit is contained in:
@@ -69,6 +69,7 @@ import { isInvalidParentFrameOrigin, shouldProcessMessage } from "../Utils/Messa
|
||||
import { get, getReadOnlyKeys, listKeys } from "../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
||||
import * as Types from "../Utils/arm/generatedClients/cosmos/types";
|
||||
import { applyExplorerBindings } from "../applyExplorerBindings";
|
||||
import { THEME_MODE_DARK, useThemeStore } from "./useTheme";
|
||||
|
||||
// This hook will create a new instance of Explorer.ts and bind it to the DOM
|
||||
// This hook has a LOT of magic, but ideally we can delete it once we have removed KO and switched entirely to React
|
||||
@@ -992,6 +993,21 @@ function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) {
|
||||
userContext.features.publicGallery = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle initial theme from portal
|
||||
if (inputs.theme && inputs.theme.mode !== undefined) {
|
||||
const isDark = inputs.theme.mode === THEME_MODE_DARK;
|
||||
useThemeStore.setState({
|
||||
isDarkMode: isDark,
|
||||
themeMode: inputs.theme.mode,
|
||||
});
|
||||
|
||||
if (isDark) {
|
||||
document.body.classList.add("isDarkMode");
|
||||
} else {
|
||||
document.body.classList.remove("isDarkMode");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface PortalMessage {
|
||||
|
||||
@@ -66,7 +66,11 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
||||
}
|
||||
},
|
||||
activateNewTab: (tab: TabsBase): void => {
|
||||
set((state) => ({ openedTabs: [...state.openedTabs, tab], activeTab: tab, activeReactTab: undefined }));
|
||||
set((state) => ({
|
||||
openedTabs: [...state.openedTabs, tab],
|
||||
activeTab: tab,
|
||||
activeReactTab: undefined as ReactTabKind | undefined,
|
||||
}));
|
||||
tab.triggerPersistState = get().persistTabsState;
|
||||
tab.onActivate();
|
||||
get().persistTabsState();
|
||||
@@ -115,7 +119,7 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
||||
set({ activeTab: undefined, activeReactTab: undefined });
|
||||
}
|
||||
|
||||
if (tab.tabId === activeTab?.tabId && tabIndex !== -1) {
|
||||
if (activeTab && tab.tabId === activeTab.tabId && tabIndex !== -1) {
|
||||
const tabToTheRight = updatedTabs[tabIndex];
|
||||
const lastOpenTab = updatedTabs[updatedTabs.length - 1];
|
||||
const newActiveTab = tabToTheRight ?? lastOpenTab;
|
||||
|
||||
86
src/hooks/useTheme.tsx
Normal file
86
src/hooks/useTheme.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import { sendMessage } from "Common/MessageHandler";
|
||||
import { MessageTypes } from "Contracts/MessageTypes";
|
||||
import { shouldProcessMessage } from "Utils/MessageValidation";
|
||||
import create from "zustand";
|
||||
|
||||
// Theme mode constants matching Portal's theme values
|
||||
export const THEME_MODE_LIGHT = 0;
|
||||
export const THEME_MODE_DARK = 1;
|
||||
|
||||
export interface ThemeStore {
|
||||
isDarkMode: boolean;
|
||||
themeMode: number;
|
||||
toggleTheme: () => void;
|
||||
}
|
||||
|
||||
export const useThemeStore = create<ThemeStore>((set) => ({
|
||||
isDarkMode: false,
|
||||
themeMode: THEME_MODE_LIGHT,
|
||||
toggleTheme: () =>
|
||||
set((state) => {
|
||||
const newIsDarkMode = !state.isDarkMode;
|
||||
const newThemeMode = newIsDarkMode ? THEME_MODE_DARK : THEME_MODE_LIGHT;
|
||||
|
||||
if (newIsDarkMode) {
|
||||
document.body.classList.add("isDarkMode");
|
||||
} else {
|
||||
document.body.classList.remove("isDarkMode");
|
||||
}
|
||||
sendMessage({
|
||||
type: MessageTypes.UpdateTheme,
|
||||
params: {
|
||||
theme: {
|
||||
mode: newThemeMode,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
isDarkMode: newIsDarkMode,
|
||||
themeMode: newThemeMode,
|
||||
};
|
||||
}),
|
||||
}));
|
||||
|
||||
// Portal theme communication
|
||||
if (typeof window !== "undefined") {
|
||||
window.addEventListener("message", (event) => {
|
||||
if (
|
||||
!shouldProcessMessage(event) ||
|
||||
event.data.data.type !== MessageTypes.UpdateTheme ||
|
||||
!event.data.data.theme ||
|
||||
event.data.data.theme.mode === undefined
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const themeMode = event.data.data.theme.mode;
|
||||
const isDark = themeMode === THEME_MODE_DARK;
|
||||
|
||||
useThemeStore.setState({
|
||||
isDarkMode: isDark,
|
||||
themeMode: themeMode,
|
||||
});
|
||||
|
||||
if (isDark) {
|
||||
document.body.classList.add("isDarkMode");
|
||||
} else {
|
||||
document.body.classList.remove("isDarkMode");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Exports
|
||||
export const isDarkMode = () => useThemeStore.getState().isDarkMode;
|
||||
|
||||
export const useTheme = () => {
|
||||
const { isDarkMode } = useThemeStore();
|
||||
return { isDarkMode };
|
||||
};
|
||||
|
||||
export const useMonacoTheme = () => {
|
||||
const { isDarkMode } = useThemeStore();
|
||||
return isDarkMode ? "vs-dark" : "vs";
|
||||
};
|
||||
|
||||
export const monacoTheme = () => (useThemeStore.getState().isDarkMode ? "vs-dark" : "vs");
|
||||
Reference in New Issue
Block a user