mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-05-12 11:23:49 +01:00
Updated theme on sidebar
This commit is contained in:
parent
f2d6bbf54e
commit
b5976fb034
@ -8,9 +8,8 @@ import {
|
||||
MenuList,
|
||||
MenuPopover,
|
||||
MenuTrigger,
|
||||
mergeClasses,
|
||||
shorthands,
|
||||
SplitButton,
|
||||
SplitButton
|
||||
} from "@fluentui/react-components";
|
||||
import { Add16Regular, ArrowSync12Regular, ChevronLeft12Regular, ChevronRight12Regular } from "@fluentui/react-icons";
|
||||
import { configContext, Platform } from "ConfigContext";
|
||||
@ -18,7 +17,6 @@ import Explorer from "Explorer/Explorer";
|
||||
import { AddDatabasePanel } from "Explorer/Panes/AddDatabasePanel/AddDatabasePanel";
|
||||
import { Tabs } from "Explorer/Tabs/Tabs";
|
||||
import { CosmosFluentProvider, cosmosShorthands, tokens } from "Explorer/Theme/ThemeUtil";
|
||||
import { ResourceTree } from "Explorer/Tree/ResourceTree";
|
||||
import { useDatabases } from "Explorer/useDatabases";
|
||||
import { KeyboardAction, KeyboardActionGroup, KeyboardActionHandler, useKeyboardActionGroup } from "KeyboardShortcuts";
|
||||
import { isFabric, isFabricMirrored, isFabricNative } from "Platform/Fabric/FabricUtil";
|
||||
@ -26,8 +24,10 @@ import { userContext } from "UserContext";
|
||||
import { getCollectionName, getDatabaseName } from "Utils/APITypeUtils";
|
||||
import { Allotment, AllotmentHandle } from "allotment";
|
||||
import { useSidePanel } from "hooks/useSidePanel";
|
||||
import { useTheme } from "hooks/useTheme";
|
||||
import { debounce } from "lodash";
|
||||
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
||||
import { ResourceTree } from "./Tree/ResourceTree";
|
||||
|
||||
const useSidebarStyles = makeStyles({
|
||||
sidebar: {
|
||||
@ -35,38 +35,67 @@ const useSidebarStyles = makeStyles({
|
||||
},
|
||||
sidebarContainer: {
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
borderRight: `1px solid ${tokens.colorNeutralStroke1}`,
|
||||
transition: "all 0.2s ease-in-out",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
backgroundColor: tokens.colorNeutralBackground1,
|
||||
position: "relative",
|
||||
},
|
||||
expandedContent: {
|
||||
display: "grid",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
gridTemplateRows: `calc(${tokens.layoutRowHeight} * 2) 1fr`,
|
||||
},
|
||||
floatingControlsContainer: {
|
||||
position: "relative",
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
zIndex: 1000,
|
||||
width: "100%",
|
||||
width: "auto",
|
||||
padding: tokens.spacingHorizontalS,
|
||||
},
|
||||
floatingControls: {
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
position: "absolute",
|
||||
right: 0,
|
||||
gap: tokens.spacingHorizontalXS,
|
||||
},
|
||||
floatingControlButton: {
|
||||
...shorthands.border("none"),
|
||||
backgroundColor: "transparent",
|
||||
color: tokens.colorNeutralForeground1,
|
||||
cursor: "pointer",
|
||||
padding: tokens.spacingHorizontalXS,
|
||||
borderRadius: tokens.borderRadiusMedium,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
":hover": {
|
||||
backgroundColor: tokens.colorNeutralBackground1Hover,
|
||||
color: tokens.colorNeutralForeground1,
|
||||
},
|
||||
":active": {
|
||||
backgroundColor: tokens.colorNeutralBackground1Pressed,
|
||||
color: tokens.colorNeutralForeground1,
|
||||
},
|
||||
":disabled": {
|
||||
color: tokens.colorNeutralForegroundDisabled,
|
||||
cursor: "not-allowed",
|
||||
},
|
||||
},
|
||||
globalCommandsContainer: {
|
||||
display: "grid",
|
||||
alignItems: "center",
|
||||
justifyItems: "center",
|
||||
width: "100%",
|
||||
containerType: "size", // Use this container for "@container" queries below this.
|
||||
containerType: "size",
|
||||
padding: tokens.spacingHorizontalS,
|
||||
...cosmosShorthands.borderBottom(),
|
||||
backgroundColor: tokens.colorNeutralBackground1,
|
||||
},
|
||||
loadingProgressBar: {
|
||||
// Float above the content
|
||||
position: "absolute",
|
||||
width: "100%",
|
||||
height: "2px",
|
||||
@ -76,7 +105,7 @@ const useSidebarStyles = makeStyles({
|
||||
animationDuration: "3s",
|
||||
animationName: {
|
||||
"0%": {
|
||||
opacity: ".2", // matches indeterminate bar width
|
||||
opacity: ".2",
|
||||
},
|
||||
"50%": {
|
||||
opacity: "1",
|
||||
@ -98,6 +127,13 @@ const useSidebarStyles = makeStyles({
|
||||
display: "flex",
|
||||
},
|
||||
},
|
||||
treeContainer: {
|
||||
flex: 1,
|
||||
overflow: "auto",
|
||||
paddingLeft: tokens.spacingHorizontalM,
|
||||
backgroundColor: tokens.colorNeutralBackground1,
|
||||
color: tokens.colorNeutralForeground1,
|
||||
},
|
||||
});
|
||||
|
||||
interface GlobalCommandsProps {
|
||||
@ -250,6 +286,7 @@ export const SidebarContainer: React.FC<SidebarProps> = ({ explorer }) => {
|
||||
const [expandedSize, setExpandedSize] = React.useState(300);
|
||||
const hasSidebar = userContext.apiType !== "Postgres" && userContext.apiType !== "VCoreMongo";
|
||||
const allotment = useRef<AllotmentHandle>(null);
|
||||
const { isDarkMode } = useTheme();
|
||||
|
||||
const expand = useCallback(() => {
|
||||
if (!expanded) {
|
||||
@ -304,7 +341,7 @@ export const SidebarContainer: React.FC<SidebarProps> = ({ explorer }) => {
|
||||
{hasSidebar && (
|
||||
// When collapsed, we force the pane to 24 pixels wide and make it non-resizable.
|
||||
<Allotment.Pane minSize={24} preferredSize={250}>
|
||||
<CosmosFluentProvider className={mergeClasses(styles.sidebar)}>
|
||||
<CosmosFluentProvider>
|
||||
<div className={styles.sidebarContainer}>
|
||||
{loading && (
|
||||
// The Fluent UI progress bar has some issues in reduced-motion environments so we use a simple CSS animation here.
|
||||
@ -335,12 +372,11 @@ export const SidebarContainer: React.FC<SidebarProps> = ({ explorer }) => {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={styles.expandedContent}
|
||||
style={!hasGlobalCommands ? { gridTemplateRows: "1fr" } : undefined}
|
||||
>
|
||||
<div className={styles.expandedContent} style={!hasGlobalCommands ? { gridTemplateRows: "1fr" } : undefined}>
|
||||
{hasGlobalCommands && <GlobalCommands explorer={explorer} />}
|
||||
<ResourceTree explorer={explorer} />
|
||||
<div className={styles.treeContainer}>
|
||||
<ResourceTree explorer={explorer} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
|
@ -4,16 +4,19 @@ import {
|
||||
FluentProvider,
|
||||
FluentProviderSlots,
|
||||
Theme,
|
||||
createDarkTheme,
|
||||
createLightTheme,
|
||||
makeStyles,
|
||||
mergeClasses,
|
||||
shorthands,
|
||||
themeToTokensObject,
|
||||
webLightTheme,
|
||||
webDarkTheme,
|
||||
webLightTheme
|
||||
} from "@fluentui/react-components";
|
||||
import { Platform, configContext } from "ConfigContext";
|
||||
import React from "react";
|
||||
import { appThemeFabricTealBrandRamp } from "../../Platform/Fabric/FabricTheme";
|
||||
import { useTheme } from "../../hooks/useTheme";
|
||||
|
||||
export const LayoutConstants = {
|
||||
rowHeight: 32,
|
||||
@ -47,6 +50,7 @@ export const CosmosFluentProvider: React.FC<CosmosFluentProviderProps> = ({ chil
|
||||
// As we convert components to Fluent UI 9, if we end up with nested FluentProviders, the inner FluentProvider will be a no-op.
|
||||
const { isInFluentProvider } = React.useContext(FluentProviderContext);
|
||||
const styles = useDefaultRootStyles();
|
||||
const { isDarkMode } = useTheme();
|
||||
|
||||
if (isInFluentProvider) {
|
||||
// We're already in a fluent context, don't create another.
|
||||
@ -61,7 +65,7 @@ export const CosmosFluentProvider: React.FC<CosmosFluentProviderProps> = ({ chil
|
||||
return (
|
||||
<FluentProviderContext.Provider value={{ isInFluentProvider: true }}>
|
||||
<FluentProvider
|
||||
theme={getPlatformTheme(configContext.platform)}
|
||||
theme={getPlatformTheme(configContext.platform, isDarkMode)}
|
||||
className={mergeClasses(styles.fluentProvider, className)}
|
||||
{...props}
|
||||
>
|
||||
@ -114,7 +118,16 @@ const cosmosTheme = {
|
||||
sidebarInitialWidth: "300px",
|
||||
};
|
||||
|
||||
export const tokens = themeToTokensObject({ ...webLightTheme, ...cosmosTheme, ...sizeMappings[LayoutSize.Compact] });
|
||||
// Get the current theme tokens based on the root theme
|
||||
export const getThemeTokens = (isDarkMode: boolean) =>
|
||||
themeToTokensObject({
|
||||
...(isDarkMode ? webDarkTheme : webLightTheme),
|
||||
...cosmosTheme,
|
||||
...sizeMappings[LayoutSize.Compact]
|
||||
});
|
||||
|
||||
// Initialize with light theme, will be updated by the provider
|
||||
export const tokens = getThemeTokens(false);
|
||||
|
||||
export const cosmosShorthands = {
|
||||
border: () => shorthands.border("1px", "solid", tokens.colorNeutralStroke2),
|
||||
@ -124,11 +137,12 @@ export const cosmosShorthands = {
|
||||
borderLeft: () => shorthands.borderLeft("1px", "solid", tokens.colorNeutralStroke2),
|
||||
};
|
||||
|
||||
export function getPlatformTheme(platform: Platform): CosmosTheme {
|
||||
export function getPlatformTheme(platform: Platform, isDarkMode: boolean = false): CosmosTheme {
|
||||
const createTheme = isDarkMode ? createDarkTheme : createLightTheme;
|
||||
const baseTheme =
|
||||
platform === Platform.Fabric
|
||||
? createLightTheme(appThemeFabricTealBrandRamp)
|
||||
: createLightTheme(appThemePortalBrandRamp);
|
||||
? createTheme(appThemeFabricTealBrandRamp)
|
||||
: createTheme(appThemePortalBrandRamp);
|
||||
|
||||
return {
|
||||
...baseTheme,
|
||||
|
24
src/Main.tsx
24
src/Main.tsx
@ -11,7 +11,7 @@ import { SQLQuickstartTutorial } from "Explorer/Quickstart/Tutorials/SQLQuicksta
|
||||
import "allotment/dist/style.css";
|
||||
import "bootstrap/dist/css/bootstrap.css";
|
||||
import { useCarousel } from "hooks/useCarousel";
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import "../externals/jquery-ui.min.css";
|
||||
import "../externals/jquery-ui.min.js";
|
||||
@ -82,7 +82,6 @@ const App = (): JSX.Element => {
|
||||
const isCopilotCarouselOpen = useCarousel((state) => state.showCopilotCarousel);
|
||||
const styles = useStyles();
|
||||
|
||||
console.log("App - Current theme: Dark");
|
||||
|
||||
if (config?.platform === Platform.Fabric) {
|
||||
loadTheme(appThemeFabric);
|
||||
@ -140,13 +139,22 @@ const Root: React.FC = () => {
|
||||
// Force dark theme
|
||||
const isDarkMode = true;
|
||||
const currentTheme = isDarkMode ? webDarkTheme : webLightTheme;
|
||||
const theme = "Dark";
|
||||
|
||||
console.log("Root component - Theme state:", {
|
||||
isDarkMode,
|
||||
currentTheme,
|
||||
theme
|
||||
});
|
||||
// Apply theme to body for Fluent UI v8 components
|
||||
useEffect(() => {
|
||||
if (isDarkMode) {
|
||||
document.body.classList.add("isDarkMode");
|
||||
loadTheme(appThemeFabric);
|
||||
} else {
|
||||
document.body.classList.remove("isDarkMode");
|
||||
loadTheme(appThemeFabric);
|
||||
}
|
||||
}, [isDarkMode]);
|
||||
|
||||
// console.log("Root component - Theme state:", {
|
||||
// isDarkMode,
|
||||
// currentTheme
|
||||
// });
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
|
@ -20,15 +20,27 @@ export const CustomThemeProvider: FC<ThemeProviderProps> = ({ children, theme })
|
||||
|
||||
export const useTheme = () => {
|
||||
const { targetDocument } = useFluent();
|
||||
const context = React.useContext(ThemeContext);
|
||||
|
||||
const [isDarkMode, setIsDarkMode] = useState(() => {
|
||||
const hasDarkMode = targetDocument?.body.classList.contains("isDarkMode") ?? true;
|
||||
return hasDarkMode;
|
||||
// First check if we're in a theme context
|
||||
if (context) {
|
||||
return context.isDarkMode;
|
||||
}
|
||||
// Fallback to checking body class
|
||||
return targetDocument?.body.classList.contains("isDarkMode") ?? true;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!targetDocument) return;
|
||||
|
||||
const checkTheme = () => {
|
||||
// First check if we're in a theme context
|
||||
if (context) {
|
||||
setIsDarkMode(context.isDarkMode);
|
||||
return;
|
||||
}
|
||||
// Fallback to checking body class
|
||||
const hasDarkMode = targetDocument.body.classList.contains("isDarkMode");
|
||||
setIsDarkMode(hasDarkMode);
|
||||
};
|
||||
@ -43,7 +55,7 @@ export const useTheme = () => {
|
||||
observer.observe(targetDocument.body, { attributes: true, attributeFilter: ["class"] });
|
||||
|
||||
return () => observer.disconnect();
|
||||
}, [targetDocument]);
|
||||
}, [targetDocument, context]);
|
||||
|
||||
return {
|
||||
isDarkMode
|
||||
|
Loading…
x
Reference in New Issue
Block a user