First dark theme commit for command bar

This commit is contained in:
Sakshi Gupta 2025-04-17 19:26:25 +05:30
parent 32576f50d3
commit f2d6bbf54e
9 changed files with 273 additions and 63 deletions

View File

@ -5,7 +5,7 @@ import {
TriggerDefinition, TriggerDefinition,
UserDefinedFunctionDefinition, UserDefinedFunctionDefinition,
} from "@azure/cosmos"; } from "@azure/cosmos";
import Explorer from "../Explorer/Explorer"; import type Explorer from "../Explorer/Explorer";
import { ConsoleData } from "../Explorer/Menus/NotificationConsole/ConsoleData"; import { ConsoleData } from "../Explorer/Menus/NotificationConsole/ConsoleData";
import { CassandraTableKey, CassandraTableKeys } from "../Explorer/Tables/TableDataClient"; import { CassandraTableKey, CassandraTableKeys } from "../Explorer/Tables/TableDataClient";
import ConflictId from "../Explorer/Tree/ConflictId"; import ConflictId from "../Explorer/Tree/ConflictId";
@ -462,3 +462,6 @@ export interface DropdownOption<T> {
value: T; value: T;
disable?: boolean; disable?: boolean;
} }
// Remove the duplicate Explorer interface and export the type
export type { Explorer };

View File

@ -0,0 +1,29 @@
import { makeStyles } from "@fluentui/react-components";
import React from "react";
import type { Explorer } from "../Contracts/ViewModels";
import { useTheme } from "../hooks/useTheme";
interface DataExplorerProps {
dataExplorer: Explorer;
}
const useStyles = makeStyles({
root: {
backgroundColor: "var(--colorNeutralBackground1)",
color: "var(--colorNeutralForeground1)",
height: "100%",
width: "100%"
}
});
export const DataExplorer: React.FC<DataExplorerProps> = ({ dataExplorer }) => {
const { isDarkMode } = useTheme();
const styles = useStyles();
return (
<div className={`dataExplorerContainer ${styles.root}`}>
<div>Data Explorer Content</div>
</div>
);
};

View File

@ -0,0 +1,37 @@
import React, { Component, ErrorInfo, ReactNode } from "react";
interface Props {
children: ReactNode;
}
interface State {
hasError: boolean;
error: Error | null;
}
export class ErrorBoundary extends Component<Props, State> {
public state: State = {
hasError: false,
error: null,
};
public static getDerivedStateFromError(error: Error): State {
return { hasError: true, error };
}
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
}
public render() {
if (this.state.hasError) {
return (
<div style={{ padding: "20px", color: "red" }}>
<h2>Something went wrong.</h2>
<details style={{ whiteSpace: "pre-wrap" }}>{this.state.error && this.state.error.toString()}</details>
</div>
);
}
return this.props.children;
}
}

View File

@ -4,11 +4,10 @@
padding: @SmallSpace 0px @SmallSpace 0px; padding: @SmallSpace 0px @SmallSpace 0px;
.flex-display(); .flex-display();
span { span {
border-left: @ButtonBorderWidth solid @BaseMediumHigh;
margin: 0 10px 0 10px; margin: 0 10px 0 10px;
} }
} }
.commandBarContainer { .commandBarContainer {
border-bottom: 1px solid @BaseMedium; border-bottom: 1px solid var(--colorNeutralStroke1);
} }

View File

@ -4,6 +4,7 @@
* and update any knockout observables passed from the parent. * and update any knockout observables passed from the parent.
*/ */
import { CommandBar as FluentCommandBar, ICommandBarItemProps } from "@fluentui/react"; import { CommandBar as FluentCommandBar, ICommandBarItemProps } from "@fluentui/react";
import { makeStyles, useFluent } from "@fluentui/react-components";
import { useNotebook } from "Explorer/Notebook/useNotebook"; import { useNotebook } from "Explorer/Notebook/useNotebook";
import { KeyboardActionGroup, useKeyboardActionGroup } from "KeyboardShortcuts"; import { KeyboardActionGroup, useKeyboardActionGroup } from "KeyboardShortcuts";
import { isFabric } from "Platform/Fabric/FabricUtil"; import { isFabric } from "Platform/Fabric/FabricUtil";
@ -11,7 +12,6 @@ import { userContext } from "UserContext";
import * as React from "react"; import * as React from "react";
import create, { UseStore } from "zustand"; import create, { UseStore } from "zustand";
import { ConnectionStatusType, PoolIdType } from "../../../Common/Constants"; import { ConnectionStatusType, PoolIdType } from "../../../Common/Constants";
import { StyleConstants } from "../../../Common/StyleConstants";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent"; import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
import Explorer from "../../Explorer"; import Explorer from "../../Explorer";
import { useSelectedNode } from "../../useSelectedNode"; import { useSelectedNode } from "../../useSelectedNode";
@ -30,18 +30,26 @@ export interface CommandBarStore {
} }
export const useCommandBar: UseStore<CommandBarStore> = create((set) => ({ export const useCommandBar: UseStore<CommandBarStore> = create((set) => ({
contextButtons: [], contextButtons: [] as CommandButtonComponentProps[],
setContextButtons: (contextButtons: CommandButtonComponentProps[]) => set((state) => ({ ...state, contextButtons })), setContextButtons: (contextButtons: CommandButtonComponentProps[]) => set((state) => ({ ...state, contextButtons })),
isHidden: false, isHidden: false,
setIsHidden: (isHidden: boolean) => set((state) => ({ ...state, isHidden })), setIsHidden: (isHidden: boolean) => set((state) => ({ ...state, isHidden })),
})); }));
const useStyles = makeStyles({
commandBarContainer: {
borderBottom: "1px solid var(--colorNeutralStroke1)"
}
});
export const CommandBar: React.FC<Props> = ({ container }: Props) => { export const CommandBar: React.FC<Props> = ({ container }: Props) => {
const selectedNodeState = useSelectedNode(); const selectedNodeState = useSelectedNode();
const buttons = useCommandBar((state) => state.contextButtons); const buttons = useCommandBar((state) => state.contextButtons);
const isHidden = useCommandBar((state) => state.isHidden); const isHidden = useCommandBar((state) => state.isHidden);
const backgroundColor = StyleConstants.BaseLight; const { targetDocument } = useFluent();
// const isDarkMode = targetDocument?.body.classList.contains("isDarkMode");
const setKeyboardHandlers = useKeyboardActionGroup(KeyboardActionGroup.COMMAND_BAR); const setKeyboardHandlers = useKeyboardActionGroup(KeyboardActionGroup.COMMAND_BAR);
const styles = useStyles();
if (userContext.apiType === "Postgres" || userContext.apiType === "VCoreMongo") { if (userContext.apiType === "Postgres" || userContext.apiType === "VCoreMongo") {
const buttons = const buttons =
@ -49,12 +57,15 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
? CommandBarComponentButtonFactory.createPostgreButtons(container) ? CommandBarComponentButtonFactory.createPostgreButtons(container)
: CommandBarComponentButtonFactory.createVCoreMongoButtons(container); : CommandBarComponentButtonFactory.createVCoreMongoButtons(container);
return ( return (
<div className="commandBarContainer" style={{ display: isHidden ? "none" : "initial" }}> <div className={styles.commandBarContainer} style={{ display: isHidden ? "none" : "initial" }}>
<FluentCommandBar <FluentCommandBar
ariaLabel="Use left and right arrow keys to navigate between commands" ariaLabel="Use left and right arrow keys to navigate between commands"
items={CommandBarUtil.convertButton(buttons, backgroundColor)} items={CommandBarUtil.convertButton(buttons, "var(--colorNeutralBackground1)")}
styles={{ styles={{
root: { backgroundColor: backgroundColor }, root: {
backgroundColor: "var(--colorNeutralBackground1)",
color: "var(--colorNeutralForeground1)"
}
}} }}
overflowButtonProps={{ ariaLabel: "More commands" }} overflowButtonProps={{ ariaLabel: "More commands" }}
/> />
@ -68,18 +79,18 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
); );
const controlButtons = CommandBarComponentButtonFactory.createControlCommandBarButtons(container); const controlButtons = CommandBarComponentButtonFactory.createControlCommandBarButtons(container);
const uiFabricStaticButtons = CommandBarUtil.convertButton(staticButtons, backgroundColor); const uiFabricStaticButtons = CommandBarUtil.convertButton(staticButtons, "var(--colorNeutralBackground1)");
if (buttons && buttons.length > 0) { if (buttons && buttons.length > 0) {
uiFabricStaticButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true)); uiFabricStaticButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
} }
const uiFabricTabsButtons: ICommandBarItemProps[] = CommandBarUtil.convertButton(contextButtons, backgroundColor); const uiFabricTabsButtons: ICommandBarItemProps[] = CommandBarUtil.convertButton(contextButtons, "var(--colorNeutralBackground1)");
if (uiFabricTabsButtons.length > 0) { if (uiFabricTabsButtons.length > 0) {
uiFabricStaticButtons.push(CommandBarUtil.createDivider("commandBarDivider")); uiFabricStaticButtons.push(CommandBarUtil.createDivider("commandBarDivider"));
} }
const uiFabricControlButtons = CommandBarUtil.convertButton(controlButtons, backgroundColor); const uiFabricControlButtons = CommandBarUtil.convertButton(controlButtons, "var(--colorNeutralBackground1)");
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true)); uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
const connectionInfo = useNotebook((state) => state.connectionInfo); const connectionInfo = useNotebook((state) => state.connectionInfo);
@ -96,14 +107,16 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
const rootStyle = isFabric() const rootStyle = isFabric()
? { ? {
root: { root: {
backgroundColor: "transparent", backgroundColor: "var(--colorNeutralBackground1)",
padding: "2px 8px 0px 8px", padding: "2px 8px 0px 8px",
}, color: "var(--colorNeutralForeground1)"
}
} }
: { : {
root: { root: {
backgroundColor: backgroundColor, backgroundColor: "var(--colorNeutralBackground1)",
}, color: "var(--colorNeutralForeground1)"
}
}; };
const allButtons = staticButtons.concat(contextButtons).concat(controlButtons); const allButtons = staticButtons.concat(contextButtons).concat(controlButtons);
@ -111,7 +124,7 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
setKeyboardHandlers(keyboardHandlers); setKeyboardHandlers(keyboardHandlers);
return ( return (
<div className="commandBarContainer" style={{ display: isHidden ? "none" : "initial" }}> <div className={styles.commandBarContainer} style={{ display: isHidden ? "none" : "initial" }}>
<FluentCommandBar <FluentCommandBar
ariaLabel="Use left and right arrow keys to navigate between commands" ariaLabel="Use left and right arrow keys to navigate between commands"
items={uiFabricStaticButtons.concat(uiFabricTabsButtons)} items={uiFabricStaticButtons.concat(uiFabricTabsButtons)}

View File

@ -1,10 +1,10 @@
import { import {
Dropdown, Dropdown,
ICommandBarItemProps, ICommandBarItemProps,
IComponentAsProps, IComponentAsProps,
IconType, IconType,
IDropdownOption, IDropdownOption,
IDropdownStyles, IDropdownStyles,
} from "@fluentui/react"; } from "@fluentui/react";
import { useQueryCopilot } from "hooks/useQueryCopilot"; import { useQueryCopilot } from "hooks/useQueryCopilot";
import { KeyboardHandlerMap } from "KeyboardShortcuts"; import { KeyboardHandlerMap } from "KeyboardShortcuts";
@ -53,7 +53,7 @@ export const convertButton = (btns: CommandButtonComponentProps[], backgroundCol
const result: ICommandBarItemProps = { const result: ICommandBarItemProps = {
iconProps: { iconProps: {
style: { style: {
width: StyleConstants.CommandBarIconWidth, // 16 width: StyleConstants.CommandBarIconWidth,
alignSelf: btn.iconName ? "baseline" : undefined, alignSelf: btn.iconName ? "baseline" : undefined,
filter: getFilter(btn.disabled), filter: getFilter(btn.disabled),
}, },
@ -79,7 +79,7 @@ export const convertButton = (btns: CommandButtonComponentProps[], backgroundCol
"data-test": `CommandBar/Button:${label}`, "data-test": `CommandBar/Button:${label}`,
buttonStyles: { buttonStyles: {
root: { root: {
backgroundColor: backgroundColor, backgroundColor: "var(--colorNeutralBackground1)",
height: buttonHeightPx, height: buttonHeightPx,
paddingRight: 0, paddingRight: 0,
paddingLeft: 0, paddingLeft: 0,
@ -87,15 +87,29 @@ export const convertButton = (btns: CommandButtonComponentProps[], backgroundCol
minWidth: 24, minWidth: 24,
marginLeft: isSplit ? 0 : 5, marginLeft: isSplit ? 0 : 5,
marginRight: isSplit ? 0 : 5, marginRight: isSplit ? 0 : 5,
color: "var(--colorNeutralForeground1)",
selectors: {
"&:hover": {
backgroundColor: "var(--colorNeutralBackground1Hover)",
color: "var(--colorNeutralForeground1)"
},
"&:active": {
backgroundColor: "var(--colorNeutralBackground1Pressed)",
color: "var(--colorNeutralForeground1)"
}
}
}, },
rootDisabled: { rootDisabled: {
backgroundColor: backgroundColor, backgroundColor: "var(--colorNeutralBackground1)",
pointerEvents: "auto", pointerEvents: "auto",
color: "var(--colorNeutralForegroundDisabled)"
}, },
splitButtonMenuButton: { splitButtonMenuButton: {
backgroundColor: backgroundColor, backgroundColor: "var(--colorNeutralBackground1)",
selectors: { selectors: {
":hover": { backgroundColor: hoverColor }, ":hover": {
backgroundColor: "var(--colorNeutralBackground1Hover)"
},
}, },
width: 16, width: 16,
}, },
@ -104,13 +118,22 @@ export const convertButton = (btns: CommandButtonComponentProps[], backgroundCol
configContext.platform == Platform.Fabric configContext.platform == Platform.Fabric
? StyleConstants.DefaultFontSize ? StyleConstants.DefaultFontSize
: StyleConstants.mediumFontSize, : StyleConstants.mediumFontSize,
color: "var(--colorNeutralForeground1)"
},
rootHovered: {
backgroundColor: "var(--colorNeutralBackground1Hover)",
color: "var(--colorNeutralForeground1)"
},
rootPressed: {
backgroundColor: "var(--colorNeutralBackground1Pressed)",
color: "var(--colorNeutralForeground1)"
}, },
rootHovered: { backgroundColor: hoverColor },
rootPressed: { backgroundColor: hoverColor },
splitButtonMenuButtonExpanded: { splitButtonMenuButtonExpanded: {
backgroundColor: StyleConstants.AccentExtra, backgroundColor: "var(--colorNeutralBackground1Pressed)",
selectors: { selectors: {
":hover": { backgroundColor: hoverColor }, ":hover": {
backgroundColor: "var(--colorNeutralBackground1Hover)"
},
}, },
}, },
splitButtonDivider: { splitButtonDivider: {
@ -119,6 +142,7 @@ export const convertButton = (btns: CommandButtonComponentProps[], backgroundCol
icon: { icon: {
paddingLeft: 0, paddingLeft: 0,
paddingRight: 0, paddingRight: 0,
color: "var(--colorNeutralForeground1)"
}, },
splitButtonContainer: { splitButtonContainer: {
marginLeft: 5, marginLeft: 5,

View File

@ -40,6 +40,14 @@ export const Tabs = ({ explorer }: TabsProps): JSX.Element => {
}); });
}, [setKeyboardHandlers]); }, [setKeyboardHandlers]);
// Add useEffect to handle context buttons
useEffect(() => {
if (activeReactTab !== undefined) {
// React tabs have no context buttons
useCommandBar.getState().setContextButtons([]);
}
}, [activeReactTab]);
return ( return (
<div className="tabsManagerContainer"> <div className="tabsManagerContainer">
<div className="nav-tabs-margin"> <div className="nav-tabs-margin">
@ -259,9 +267,6 @@ const isQueryErrorThrown = (tab?: Tab, tabKind?: ReactTabKind): boolean => {
}; };
const getReactTabContent = (activeReactTab: ReactTabKind, explorer: Explorer): JSX.Element => { const getReactTabContent = (activeReactTab: ReactTabKind, explorer: Explorer): JSX.Element => {
// React tabs have no context buttons.
useCommandBar.getState().setContextButtons([]);
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
switch (activeReactTab) { switch (activeReactTab) {
case ReactTabKind.Connect: case ReactTabKind.Connect:

View File

@ -3,6 +3,8 @@ import "./ReactDevTools";
// CSS Dependencies // CSS Dependencies
import { initializeIcons, loadTheme } from "@fluentui/react"; import { initializeIcons, loadTheme } from "@fluentui/react";
import { FluentProvider, makeStyles, webDarkTheme, webLightTheme } from "@fluentui/react-components";
import { Platform } from "ConfigContext";
import { QuickstartCarousel } from "Explorer/Quickstart/QuickstartCarousel"; import { QuickstartCarousel } from "Explorer/Quickstart/QuickstartCarousel";
import { MongoQuickstartTutorial } from "Explorer/Quickstart/Tutorials/MongoQuickstartTutorial"; import { MongoQuickstartTutorial } from "Explorer/Quickstart/Tutorials/MongoQuickstartTutorial";
import { SQLQuickstartTutorial } from "Explorer/Quickstart/Tutorials/SQLQuickstartTutorial"; import { SQLQuickstartTutorial } from "Explorer/Quickstart/Tutorials/SQLQuickstartTutorial";
@ -19,7 +21,7 @@ import "../externals/jquery.dataTables.min.css";
import "../externals/jquery.typeahead.min.css"; import "../externals/jquery.typeahead.min.css";
import "../externals/jquery.typeahead.min.js"; import "../externals/jquery.typeahead.min.js";
// Image Dependencies // Image Dependencies
import { Platform } from "ConfigContext"; import { SidePanel } from "Explorer/Panes/PanelContainerComponent";
import { QueryCopilotCarousel } from "Explorer/QueryCopilot/CopilotCarousel"; import { QueryCopilotCarousel } from "Explorer/QueryCopilot/CopilotCarousel";
import { SidebarContainer } from "Explorer/Sidebar"; import { SidebarContainer } from "Explorer/Sidebar";
import { KeyboardShortcutRoot } from "KeyboardShortcuts"; import { KeyboardShortcutRoot } from "KeyboardShortcuts";
@ -46,6 +48,7 @@ import "./Explorer/Controls/ErrorDisplayComponent/ErrorDisplayComponent.less";
import "./Explorer/Controls/JsonEditor/JsonEditorComponent.less"; import "./Explorer/Controls/JsonEditor/JsonEditorComponent.less";
import "./Explorer/Controls/Notebook/NotebookTerminalComponent.less"; import "./Explorer/Controls/Notebook/NotebookTerminalComponent.less";
import "./Explorer/Controls/TreeComponent/treeComponent.less"; import "./Explorer/Controls/TreeComponent/treeComponent.less";
import { ErrorBoundary } from "./Explorer/ErrorBoundary";
import "./Explorer/Graph/GraphExplorerComponent/graphExplorer.less"; import "./Explorer/Graph/GraphExplorerComponent/graphExplorer.less";
import "./Explorer/Menus/CommandBar/CommandBarComponent.less"; import "./Explorer/Menus/CommandBar/CommandBarComponent.less";
import { CommandBar } from "./Explorer/Menus/CommandBar/CommandBarComponentAdapter"; import { CommandBar } from "./Explorer/Menus/CommandBar/CommandBarComponentAdapter";
@ -54,7 +57,6 @@ import "./Explorer/Menus/CommandBar/MemoryTrackerComponent.less";
import "./Explorer/Menus/NotificationConsole/NotificationConsole.less"; import "./Explorer/Menus/NotificationConsole/NotificationConsole.less";
import { NotificationConsole } from "./Explorer/Menus/NotificationConsole/NotificationConsoleComponent"; import { NotificationConsole } from "./Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
import "./Explorer/Panes/PanelComponent.less"; import "./Explorer/Panes/PanelComponent.less";
import { SidePanel } from "./Explorer/Panes/PanelContainerComponent";
import "./Explorer/SplashScreen/SplashScreen.less"; import "./Explorer/SplashScreen/SplashScreen.less";
import "./Libs/jquery"; import "./Libs/jquery";
import { appThemeFabric } from "./Platform/Fabric/FabricTheme"; import { appThemeFabric } from "./Platform/Fabric/FabricTheme";
@ -62,13 +64,26 @@ import "./Shared/appInsights";
import { useConfig } from "./hooks/useConfig"; import { useConfig } from "./hooks/useConfig";
import { useKnockoutExplorer } from "./hooks/useKnockoutExplorer"; import { useKnockoutExplorer } from "./hooks/useKnockoutExplorer";
initializeIcons(); // Initialize icons before React is loaded
initializeIcons(undefined, { disableWarnings: true });
const App: React.FunctionComponent = () => { const useStyles = makeStyles({
root: {
height: "100vh",
width: "100vw",
backgroundColor: "var(--colorNeutralBackground1)",
color: "var(--colorNeutralForeground1)"
}
});
const App = (): JSX.Element => {
const config = useConfig();
const isCarouselOpen = useCarousel((state) => state.shouldOpen); const isCarouselOpen = useCarousel((state) => state.shouldOpen);
const isCopilotCarouselOpen = useCarousel((state) => state.showCopilotCarousel); const isCopilotCarouselOpen = useCarousel((state) => state.showCopilotCarousel);
const styles = useStyles();
console.log("App - Current theme: Dark");
const config = useConfig();
if (config?.platform === Platform.Fabric) { if (config?.platform === Platform.Fabric) {
loadTheme(appThemeFabric); loadTheme(appThemeFabric);
import("../less/documentDBFabric.less"); import("../less/documentDBFabric.less");
@ -81,37 +96,71 @@ const App: React.FunctionComponent = () => {
} }
return ( return (
<KeyboardShortcutRoot> <div id="Main" className={styles.root}>
<div className="flexContainer" aria-hidden="false" data-test="DataExplorerRoot"> <KeyboardShortcutRoot>
<div id="divExplorer" className="flexContainer hideOverflows"> <div
<div id="freeTierTeachingBubble"> </div> className="flexContainer"
{/* Main Command Bar - Start */} style={{ flex: 1, display: "flex", flexDirection: "column" }}
<CommandBar container={explorer} /> aria-hidden="false"
{/* Collections Tree and Tabs - Begin */} data-test="DataExplorerRoot"
<SidebarContainer explorer={explorer} /> >
{/* Collections Tree and Tabs - End */}
<div <div
className="dataExplorerErrorConsoleContainer" id="divExplorer"
role="contentinfo" className="flexContainer hideOverflows"
aria-label="Notification console" style={{ flex: 1, display: "flex", flexDirection: "column" }}
id="explorerNotificationConsole"
> >
<NotificationConsole /> <div id="freeTierTeachingBubble"> </div>
{/* Main Command Bar - Start */}
<CommandBar container={explorer} />
{/* Collections Tree and Tabs - Begin */}
<SidebarContainer explorer={explorer} />
{/* Collections Tree and Tabs - End */}
<div
className="dataExplorerErrorConsoleContainer"
role="contentinfo"
aria-label="Notification console"
id="explorerNotificationConsole"
>
<NotificationConsole />
</div>
</div> </div>
<SidePanel />
<Dialog />
{<QuickstartCarousel isOpen={isCarouselOpen} />}
{<SQLQuickstartTutorial />}
{<MongoQuickstartTutorial />}
{<QueryCopilotCarousel isOpen={isCopilotCarouselOpen} explorer={explorer} />}
</div> </div>
<SidePanel /> </KeyboardShortcutRoot>
<Dialog /> </div>
{<QuickstartCarousel isOpen={isCarouselOpen} />} );
{<SQLQuickstartTutorial />} };
{<MongoQuickstartTutorial />}
{<QueryCopilotCarousel isOpen={isCopilotCarouselOpen} explorer={explorer} />} const Root: React.FC = () => {
</div> // Force dark theme
</KeyboardShortcutRoot> const isDarkMode = true;
const currentTheme = isDarkMode ? webDarkTheme : webLightTheme;
const theme = "Dark";
console.log("Root component - Theme state:", {
isDarkMode,
currentTheme,
theme
});
return (
<ErrorBoundary>
<FluentProvider theme={currentTheme}>
<App />
</FluentProvider>
</ErrorBoundary>
); );
}; };
const mainElement = document.getElementById("Main"); const mainElement = document.getElementById("Main");
ReactDOM.render(<App />, mainElement); if (mainElement) {
ReactDOM.render(<Root />, mainElement);
}
function LoadingExplorer(): JSX.Element { function LoadingExplorer(): JSX.Element {
return ( return (

51
src/hooks/useTheme.tsx Normal file
View File

@ -0,0 +1,51 @@
import { useFluent } from "@fluentui/react-components";
import React, { createContext, FC, ReactNode, useEffect, useState } from "react";
interface ThemeContextType {
theme: "Light" | "Dark";
isDarkMode: boolean;
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
interface ThemeProviderProps {
children: ReactNode;
theme: "Light" | "Dark";
}
export const CustomThemeProvider: FC<ThemeProviderProps> = ({ children, theme }) => {
const isDarkMode = theme === "Dark";
return <ThemeContext.Provider value={{ theme, isDarkMode }}>{children}</ThemeContext.Provider>;
};
export const useTheme = () => {
const { targetDocument } = useFluent();
const [isDarkMode, setIsDarkMode] = useState(() => {
const hasDarkMode = targetDocument?.body.classList.contains("isDarkMode") ?? true;
return hasDarkMode;
});
useEffect(() => {
if (!targetDocument) return;
const checkTheme = () => {
const hasDarkMode = targetDocument.body.classList.contains("isDarkMode");
setIsDarkMode(hasDarkMode);
};
// Initial check
checkTheme();
// Create a MutationObserver to watch for class changes
const observer = new MutationObserver((mutations) => {
checkTheme();
});
observer.observe(targetDocument.body, { attributes: true, attributeFilter: ["class"] });
return () => observer.disconnect();
}, [targetDocument]);
return {
isDarkMode
};
};