mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-10-13 15:28:05 +01:00
updated the theme icon for now on DE to change the theme from portal/DE it self
This commit is contained in:
parent
c42fe99c1a
commit
0bf9382eeb
3
images/moon-blue.svg
Normal file
3
images/moon-blue.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 7.5C4 5.567 5.567 4 7.5 4C8.5 4 9.4 4.4 10 5.1C9.5 4.8 8.9 4.6 8.3 4.6C6.8 4.6 5.6 5.8 5.6 7.3C5.6 8.8 6.8 10 8.3 10C8.9 10 9.5 9.8 10 9.5C9.4 10.2 8.5 10.6 7.5 10.6C5.567 10.6 4 9.033 4 7.1V7.5Z" fill="#0078D4"/>
|
||||
</svg>
|
After Width: | Height: | Size: 328 B |
11
images/sun-blue.svg
Normal file
11
images/sun-blue.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 2C6 1.44772 6.44772 1 7 1C7.55228 1 8 1.44772 8 2C8 2.55228 7.55228 3 7 3C6.44772 3 6 2.55228 6 2Z" fill="#0078D4"/>
|
||||
<path d="M6 13C6 12.4477 6.44772 12 7 12C7.55228 12 8 12.4477 8 13C8 13.5523 7.55228 14 7 14C6.44772 14 6 13.5523 6 13Z" fill="#0078D4"/>
|
||||
<path d="M1 7C1 6.44772 1.44772 6 2 6C2.55228 6 3 6.44772 3 7C3 7.55228 2.55228 8 2 8C1.44772 8 1 7.55228 1 7Z" fill="#0078D4"/>
|
||||
<path d="M12 7C12 6.44772 12.4477 6 13 6C13.5523 6 14 6.44772 14 7C14 7.55228 13.5523 8 13 8C12.4477 8 12 7.55228 12 7Z" fill="#0078D4"/>
|
||||
<path d="M2.63604 3.63604C3.02656 3.24551 3.65973 3.24551 4.05025 3.63604C4.44078 4.02656 4.44078 4.65973 4.05025 5.05025C3.65973 5.44078 3.02656 5.44078 2.63604 5.05025C2.24551 4.65973 2.24551 4.02656 2.63604 3.63604Z" fill="#0078D4"/>
|
||||
<path d="M10.9497 9.94975C11.3403 9.55922 11.9734 9.55922 12.364 9.94975C12.7545 10.3403 12.7545 10.9734 12.364 11.364C11.9734 11.7545 11.3403 11.7545 10.9497 11.364C10.5592 10.9734 10.5592 10.3403 10.9497 9.94975Z" fill="#0078D4"/>
|
||||
<path d="M10.9497 5.05025C10.5592 4.65973 10.5592 4.02656 10.9497 3.63604C11.3403 3.24551 11.9734 3.24551 12.364 3.63604C12.7545 4.02656 12.7545 4.65973 12.364 5.05025C11.9734 5.44078 11.3403 5.44078 10.9497 5.05025Z" fill="#0078D4"/>
|
||||
<path d="M2.63604 11.364C2.24551 10.9734 2.24551 10.3403 2.63604 9.94975C3.02656 9.55922 3.65973 9.55922 4.05025 9.94975C4.44078 10.3403 4.44078 10.9734 4.05025 11.364C3.65973 11.7545 3.02656 11.7545 2.63604 11.364Z" fill="#0078D4"/>
|
||||
<circle cx="7.5" cy="7.5" r="2.5" fill="#0078D4"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
@ -85,7 +85,7 @@ export class CollapsibleSectionComponent extends React.Component<CollapsibleSect
|
||||
},
|
||||
rootPressed: {
|
||||
backgroundColor: "transparent",
|
||||
}
|
||||
},
|
||||
}}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
|
@ -179,18 +179,18 @@ export const Dialog: FC = () => {
|
||||
title,
|
||||
subText,
|
||||
styles: {
|
||||
title: {
|
||||
fontSize: DIALOG_TITLE_FONT_SIZE,
|
||||
title: {
|
||||
fontSize: DIALOG_TITLE_FONT_SIZE,
|
||||
fontWeight: DIALOG_TITLE_FONT_WEIGHT,
|
||||
},
|
||||
subText: {
|
||||
subText: {
|
||||
fontSize: DIALOG_SUBTEXT_FONT_SIZE,
|
||||
color: 'var(--colorNeutralForeground2)'
|
||||
color: "var(--colorNeutralForeground2)",
|
||||
},
|
||||
content: {
|
||||
backgroundColor: 'var(--colorNeutralBackground1)',
|
||||
color: 'var(--colorNeutralForeground1)'
|
||||
}
|
||||
backgroundColor: "var(--colorNeutralBackground1)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
},
|
||||
showCloseButton: showCloseButton || false,
|
||||
onDismiss,
|
||||
@ -200,12 +200,12 @@ export const Dialog: FC = () => {
|
||||
maxWidth: DIALOG_MAX_WIDTH,
|
||||
styles: {
|
||||
main: {
|
||||
backgroundColor: 'var(--colorNeutralBackground1)',
|
||||
backgroundColor: "var(--colorNeutralBackground1)",
|
||||
selectors: {
|
||||
'.ms-Dialog-title': { color: 'var(--colorNeutralForeground1)' },
|
||||
}
|
||||
}
|
||||
}
|
||||
".ms-Dialog-title": { color: "var(--colorNeutralForeground1)" },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const primaryButtonProps: IButtonProps = {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Spinner, SpinnerSize } from "@fluentui/react";
|
||||
import { monacoTheme } from "hooks/useTheme";
|
||||
import { useThemeStore } from "hooks/useTheme";
|
||||
import * as React from "react";
|
||||
import { loadMonaco, monaco } from "../../LazyMonaco";
|
||||
// import "./EditorReact.less";
|
||||
@ -67,6 +67,7 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
|
||||
private rootNode: HTMLElement;
|
||||
public editor: monaco.editor.IStandaloneCodeEditor;
|
||||
private selectionListener: monaco.IDisposable;
|
||||
private themeUnsubscribe: () => void;
|
||||
monacoApi: {
|
||||
default: typeof monaco;
|
||||
Emitter: typeof monaco.Emitter;
|
||||
@ -95,6 +96,13 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
|
||||
public componentDidMount(): void {
|
||||
this.createEditor(this.configureEditor.bind(this));
|
||||
|
||||
this.themeUnsubscribe = useThemeStore.subscribe((state) => {
|
||||
if (this.editor) {
|
||||
const newTheme = state.isDarkMode ? "vs-dark" : "vs";
|
||||
this.monacoApi?.editor.setTheme(newTheme);
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
const suggestionWidget = this.editor?.getDomNode()?.querySelector(".suggest-widget") as HTMLElement;
|
||||
if (suggestionWidget) {
|
||||
@ -129,6 +137,7 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
this.selectionListener && this.selectionListener.dispose();
|
||||
this.themeUnsubscribe && this.themeUnsubscribe();
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
@ -212,7 +221,7 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
|
||||
ariaLabel: this.props.ariaLabel,
|
||||
fontSize: this.props.fontSize || 12,
|
||||
automaticLayout: true,
|
||||
theme: monacoTheme,
|
||||
theme: useThemeStore.getState().isDarkMode ? "vs-dark" : "vs",
|
||||
wordWrap: this.props.wordWrap || "off",
|
||||
lineNumbers: this.props.lineNumbers || "off",
|
||||
lineNumbersMinChars: this.props.lineNumbersMinChars,
|
||||
|
@ -33,7 +33,7 @@ export interface FullTextPolicyData {
|
||||
const labelStyles = {
|
||||
root: {
|
||||
fontSize: 12,
|
||||
color: "var(--colorNeutralForeground1)"
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
};
|
||||
|
||||
@ -223,31 +223,32 @@ export const FullTextPoliciesComponent: React.FunctionComponent<FullTextPolicies
|
||||
</Stack>
|
||||
</CollapsibleSectionComponent>
|
||||
))}
|
||||
<DefaultButton
|
||||
id={`add-vector-policy`}
|
||||
styles={{
|
||||
root: {
|
||||
maxWidth: 170,
|
||||
<DefaultButton
|
||||
id={`add-vector-policy`}
|
||||
styles={{
|
||||
root: {
|
||||
maxWidth: 170,
|
||||
fontSize: 12,
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "var(--colorNeutralStroke1)"
|
||||
borderColor: "var(--colorNeutralStroke1)",
|
||||
},
|
||||
rootHovered: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "var(--colorNeutralForeground1)"
|
||||
borderColor: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
rootPressed: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "var(--colorNeutralForeground1)"
|
||||
borderColor: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
rootDisabled: {
|
||||
backgroundColor: "transparent"
|
||||
}
|
||||
}}
|
||||
onClick={onAdd}>
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
}}
|
||||
onClick={onAdd}
|
||||
>
|
||||
Add full text path
|
||||
</DefaultButton>
|
||||
</Stack>
|
||||
|
@ -3,7 +3,7 @@ import * as DataModels from "Contracts/DataModels";
|
||||
import { titleAndInputStackProps, unsavedEditorWarningMessage } from "Explorer/Controls/Settings/SettingsRenderUtils";
|
||||
import { isDirty } from "Explorer/Controls/Settings/SettingsUtils";
|
||||
import { loadMonaco } from "Explorer/LazyMonaco";
|
||||
import { monacoTheme } from "hooks/useTheme";
|
||||
import { useThemeStore } from "hooks/useTheme";
|
||||
import * as monaco from "monaco-editor";
|
||||
import * as React from "react";
|
||||
export interface ComputedPropertiesComponentProps {
|
||||
@ -27,6 +27,7 @@ export class ComputedPropertiesComponent extends React.Component<
|
||||
private shouldCheckComponentIsDirty = true;
|
||||
private computedPropertiesDiv = React.createRef<HTMLDivElement>();
|
||||
private computedPropertiesEditor: monaco.editor.IStandaloneCodeEditor;
|
||||
private themeUnsubscribe: () => void;
|
||||
|
||||
constructor(props: ComputedPropertiesComponentProps) {
|
||||
super(props);
|
||||
@ -48,6 +49,10 @@ export class ComputedPropertiesComponent extends React.Component<
|
||||
this.onComponentUpdate();
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
this.themeUnsubscribe && this.themeUnsubscribe();
|
||||
}
|
||||
|
||||
public resetComputedPropertiesEditor = (): void => {
|
||||
if (!this.computedPropertiesEditor) {
|
||||
this.createComputedPropertiesEditor();
|
||||
@ -86,9 +91,17 @@ export class ComputedPropertiesComponent extends React.Component<
|
||||
value: value,
|
||||
language: "json",
|
||||
ariaLabel: "Computed properties",
|
||||
theme: monacoTheme,
|
||||
theme: useThemeStore.getState().isDarkMode ? "vs-dark" : "vs",
|
||||
});
|
||||
if (this.computedPropertiesEditor) {
|
||||
// Subscribe to theme changes
|
||||
this.themeUnsubscribe = useThemeStore.subscribe((state) => {
|
||||
if (this.computedPropertiesEditor) {
|
||||
const newTheme = state.isDarkMode ? "vs-dark" : "vs";
|
||||
monaco.editor.setTheme(newTheme);
|
||||
}
|
||||
});
|
||||
|
||||
const computedPropertiesEditorModel = this.computedPropertiesEditor.getModel();
|
||||
computedPropertiesEditorModel.onDidChangeContent(this.onEditorContentChange.bind(this));
|
||||
this.props.logComputedPropertiesSuccessMessage();
|
||||
|
@ -102,51 +102,51 @@ export const ContainerPolicyComponent: React.FC<ContainerPolicyComponentProps> =
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Pivot
|
||||
onLinkClick={onPivotChange}
|
||||
<Pivot
|
||||
onLinkClick={onPivotChange}
|
||||
selectedKey={ContainerPolicyTabTypes[selectedTab]}
|
||||
styles={{
|
||||
root: {
|
||||
color: "var(--colorNeutralForeground1)"
|
||||
root: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
link: {
|
||||
link: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent",
|
||||
selectors: {
|
||||
':hover': {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent"
|
||||
":hover": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
':active': {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent"
|
||||
}
|
||||
}
|
||||
":active": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
},
|
||||
},
|
||||
linkIsSelected: {
|
||||
linkIsSelected: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent",
|
||||
selectors: {
|
||||
':before': {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "var(--colorBrandForeground1)"
|
||||
},
|
||||
':hover': {
|
||||
":before": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent"
|
||||
backgroundColor: "var(--colorBrandForeground1)",
|
||||
},
|
||||
':active': {
|
||||
":hover": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent"
|
||||
}
|
||||
}
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
":active": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
},
|
||||
},
|
||||
linkContent: {
|
||||
color: "inherit"
|
||||
color: "inherit",
|
||||
},
|
||||
text: {
|
||||
color: "inherit"
|
||||
}
|
||||
color: "inherit",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{isVectorSearchEnabled && (
|
||||
@ -190,26 +190,26 @@ export const ContainerPolicyComponent: React.FC<ContainerPolicyComponentProps> =
|
||||
) : (
|
||||
<DefaultButton
|
||||
id={"create-full-text-policy"}
|
||||
styles={{
|
||||
root: {
|
||||
styles={{
|
||||
root: {
|
||||
fontSize: 12,
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "var(--colorNeutralForeground1)"
|
||||
borderColor: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
rootHovered: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "var(--colorNeutralForeground1)"
|
||||
borderColor: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
rootPressed: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "var(--colorNeutralForeground1)"
|
||||
borderColor: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
rootDisabled: {
|
||||
backgroundColor: "transparent"
|
||||
}
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
checkAndSendFullTextPolicyToSettings({
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { MessageBar, MessageBarType, Stack } from "@fluentui/react";
|
||||
import { monacoTheme } from "hooks/useTheme";
|
||||
import { useThemeStore } from "hooks/useTheme";
|
||||
import * as monaco from "monaco-editor";
|
||||
import * as React from "react";
|
||||
import * as DataModels from "../../../../Contracts/DataModels";
|
||||
@ -31,6 +31,7 @@ export class IndexingPolicyComponent extends React.Component<
|
||||
private shouldCheckComponentIsDirty = true;
|
||||
private indexingPolicyDiv = React.createRef<HTMLDivElement>();
|
||||
private indexingPolicyEditor: monaco.editor.IStandaloneCodeEditor;
|
||||
private themeUnsubscribe: () => void;
|
||||
|
||||
constructor(props: IndexingPolicyComponentProps) {
|
||||
super(props);
|
||||
@ -52,6 +53,10 @@ export class IndexingPolicyComponent extends React.Component<
|
||||
this.onComponentUpdate();
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
this.themeUnsubscribe && this.themeUnsubscribe();
|
||||
}
|
||||
|
||||
public resetIndexingPolicyEditor = (): void => {
|
||||
if (!this.indexingPolicyEditor) {
|
||||
this.createIndexingPolicyEditor();
|
||||
@ -98,59 +103,22 @@ export class IndexingPolicyComponent extends React.Component<
|
||||
language: "json",
|
||||
readOnly: isIndexTransforming(this.props.indexTransformationProgress),
|
||||
ariaLabel: "Indexing Policy",
|
||||
theme: monacoTheme,
|
||||
theme: useThemeStore.getState().isDarkMode ? "vs-dark" : "vs",
|
||||
});
|
||||
if (this.indexingPolicyEditor) {
|
||||
this.themeUnsubscribe = useThemeStore.subscribe((state) => {
|
||||
if (this.indexingPolicyEditor) {
|
||||
const newTheme = state.isDarkMode ? "vs-dark" : "vs";
|
||||
monaco.editor.setTheme(newTheme);
|
||||
}
|
||||
});
|
||||
|
||||
const indexingPolicyEditorModel = this.indexingPolicyEditor.getModel();
|
||||
indexingPolicyEditorModel.onDidChangeContent(this.onEditorContentChange.bind(this));
|
||||
this.props.logIndexingPolicySuccessMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
// private async createIndexingPolicyEditor(): Promise<void> {
|
||||
// const isDarkMode = true;
|
||||
// const monacoThemeName = "fluent-theme";
|
||||
|
||||
// if (!this.indexingPolicyDiv.current) return;
|
||||
|
||||
// const value: string = JSON.stringify(this.props.indexingPolicyContent, undefined, 4);
|
||||
// const monaco = await loadMonaco();
|
||||
|
||||
// // Safely get Fluent UI theme colors
|
||||
// const bodyStyles = getComputedStyle(document.body);
|
||||
// const backgroundColor = bodyStyles.getPropertyValue("--colorNeutralBackground1").trim() || "#1b1a19";
|
||||
// const foregroundColor = bodyStyles.getPropertyValue("--colorNeutralForeground1").trim() || "#ffffff";
|
||||
|
||||
// // Define Monaco theme using Fluent UI colors
|
||||
// monaco.editor.defineTheme(monacoThemeName, {
|
||||
// base: isDarkMode ? "vs-dark" : "vs",
|
||||
// inherit: true,
|
||||
// rules: [],
|
||||
// colors: {
|
||||
// "editor.background": backgroundColor,
|
||||
// "editor.foreground": foregroundColor,
|
||||
// "editorCursor.foreground": "#ffcc00",
|
||||
// "editorLineNumber.foreground": "#aaaaaa",
|
||||
// "editor.selectionBackground": "#666666",
|
||||
// "editor.lineHighlightBackground": "#333333"
|
||||
// }
|
||||
// });
|
||||
|
||||
// // Create the editor with the custom theme
|
||||
// this.indexingPolicyEditor = monaco.editor.create(this.indexingPolicyDiv.current, {
|
||||
// value,
|
||||
// language: "json",
|
||||
// readOnly: isIndexTransforming(this.props.indexTransformationProgress),
|
||||
// ariaLabel: "Indexing Policy",
|
||||
// theme: monacoThemeName
|
||||
// });
|
||||
|
||||
// if (this.indexingPolicyEditor) {
|
||||
// const indexingPolicyEditorModel = this.indexingPolicyEditor.getModel();
|
||||
// indexingPolicyEditorModel?.onDidChangeContent(this.onEditorContentChange.bind(this));
|
||||
// this.props.logIndexingPolicySuccessMessage();
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
private onEditorContentChange = (): void => {
|
||||
|
@ -77,13 +77,14 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
|
||||
onChange={(newValue) => handleBucketChange(bucket.id, newValue)}
|
||||
showValue={false}
|
||||
label={`Bucket ${bucket.id}${bucket.id === 1 ? " (Data Explorer Query Bucket)" : ""}`}
|
||||
styles={{
|
||||
styles={{
|
||||
root: { flex: 2, maxWidth: 400 },
|
||||
titleLabel: {
|
||||
color: bucket.maxThroughputPercentage === 100 ?
|
||||
"var(--colorNeutralForeground4)" :
|
||||
"var(--colorNeutralForeground1)"
|
||||
}
|
||||
titleLabel: {
|
||||
color:
|
||||
bucket.maxThroughputPercentage === 100
|
||||
? "var(--colorNeutralForeground4)"
|
||||
: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
}}
|
||||
disabled={bucket.maxThroughputPercentage === 100}
|
||||
/>
|
||||
|
@ -41,7 +41,7 @@ import {
|
||||
noLeftPaddingCheckBoxStyle,
|
||||
relaxedSpacingStackProps,
|
||||
saveThroughputWarningMessage,
|
||||
titleAndInputStackProps
|
||||
titleAndInputStackProps,
|
||||
} from "../../SettingsRenderUtils";
|
||||
import { IsComponentDirtyResult, getSanitizedInputValue, isDirty } from "../../SettingsUtils";
|
||||
import { ToolTipLabelComponent } from "../ToolTipLabelComponent";
|
||||
@ -548,7 +548,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
||||
};
|
||||
|
||||
private darkThemeMessageBarStyles: Partial<IMessageBarStyles> = {
|
||||
root: {
|
||||
root: {
|
||||
marginTop: "5px",
|
||||
selectors: {
|
||||
"&.ms-MessageBar--severeWarning": {
|
||||
@ -574,7 +574,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
||||
this.currentThroughputValue() > this.props.softAllowedMaximumThroughput ||
|
||||
this.currentThroughputValue() < this.props.minimum;
|
||||
return (
|
||||
<MessageBar
|
||||
<MessageBar
|
||||
messageBarType={isSevereWarning ? MessageBarType.severeWarning : MessageBarType.warning}
|
||||
styles={this.darkThemeMessageBarStyles}
|
||||
>
|
||||
@ -590,7 +590,10 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
||||
{/* Column 1: Minimum RU/s */}
|
||||
<Stack tokens={{ childrenGap: 4 }}>
|
||||
<Stack horizontal verticalAlign="center" tokens={{ childrenGap: 4 }}>
|
||||
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}>
|
||||
<Text
|
||||
variant="small"
|
||||
style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}
|
||||
>
|
||||
Minimum RU/s
|
||||
</Text>
|
||||
<FontIcon iconName="Info" style={{ fontSize: 12, color: "var(--colorNeutralForeground2)" }} />
|
||||
@ -631,7 +634,10 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
||||
{/* Column 3: Maximum RU/s */}
|
||||
<Stack tokens={{ childrenGap: 4 }}>
|
||||
<Stack horizontal verticalAlign="center" tokens={{ childrenGap: 4 }}>
|
||||
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}>
|
||||
<Text
|
||||
variant="small"
|
||||
style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}
|
||||
>
|
||||
Maximum RU/s
|
||||
</Text>
|
||||
<FontIcon iconName="Info" style={{ fontSize: 12, color: "var(--colorNeutralForeground2)" }} />
|
||||
@ -643,25 +649,25 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
||||
key="auto pilot throughput input"
|
||||
styles={{
|
||||
...getTextFieldStyles(this.props.maxAutoPilotThroughput, this.props.maxAutoPilotThroughputBaseline),
|
||||
fieldGroup: {
|
||||
width: 100,
|
||||
fieldGroup: {
|
||||
width: 100,
|
||||
height: 28,
|
||||
backgroundColor: "var(--colorNeutralBackground4)",
|
||||
backgroundColor: "var(--colorNeutralBackground4)",
|
||||
},
|
||||
field: {
|
||||
fontSize: 14,
|
||||
field: {
|
||||
fontSize: 14,
|
||||
fontWeight: 400,
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "var(--colorNeutralBackground4)",
|
||||
},
|
||||
root: {
|
||||
selectors: {
|
||||
"input": {
|
||||
input: {
|
||||
backgroundColor: "var(--colorNeutralBackground4)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}}
|
||||
disabled={this.overrideWithProvisionedThroughputSettings()}
|
||||
step={AutoPilotUtils.autoPilotIncrementStep}
|
||||
|
@ -54,7 +54,7 @@ export const CostEstimateText: FunctionComponent<CostEstimateTextProps> = ({
|
||||
|
||||
if (isAutoscale) {
|
||||
return (
|
||||
<Stack style={{ marginBottom: 6 , color: "var(--colorNeutralForeground1)" }}>
|
||||
<Stack style={{ marginBottom: 6, color: "var(--colorNeutralForeground1)" }}>
|
||||
<Text variant="small" style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||
{estimatedMonthlyCost} ({currency}){iconWithEstimatedCostDisclaimer}:{" "}
|
||||
<b>
|
||||
|
@ -193,7 +193,11 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
<div className="throughputInputContainer throughputInputSpacing">
|
||||
<Stack horizontal>
|
||||
<span className="mandatoryStar">* </span>
|
||||
<Text aria-label="Throughput header" variant="small" style={{ lineHeight: "20px", fontWeight: 600 , color: "var(--colorNeutralForeground1)"}}>
|
||||
<Text
|
||||
aria-label="Throughput header"
|
||||
variant="small"
|
||||
style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}
|
||||
>
|
||||
{getThroughputLabelText()}
|
||||
</Text>
|
||||
<InfoTooltip>{PricingUtils.getRuToolTipText()}</InfoTooltip>
|
||||
@ -236,14 +240,17 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
|
||||
{isAutoscaleSelected && (
|
||||
<Stack className="throughputInputSpacing">
|
||||
<Text style={{ marginTop: -2, fontSize: 12 ,color: "var(--colorNeutralForeground1)" }}>
|
||||
<Text style={{ marginTop: -2, fontSize: 12, color: "var(--colorNeutralForeground1)" }}>
|
||||
Your container throughput will automatically scale up to the maximum value you select, from a minimum of 10%
|
||||
of that value.
|
||||
</Text>
|
||||
<Stack horizontal verticalAlign="end" tokens={{ childrenGap: 8 }}>
|
||||
<Stack tokens={{ childrenGap: 4 }}>
|
||||
<Stack horizontal verticalAlign="center" tokens={{ childrenGap: 4 }}>
|
||||
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}>
|
||||
<Text
|
||||
variant="small"
|
||||
style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}
|
||||
>
|
||||
Minimum RU/s
|
||||
</Text>
|
||||
<InfoTooltip>The minimum RU/s your container will scale to</InfoTooltip>
|
||||
@ -273,7 +280,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
fontSize: 12,
|
||||
fontWeight: 400,
|
||||
paddingBottom: 6,
|
||||
color: "var(--colorNeutralForeground1)"
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
}}
|
||||
>
|
||||
x 10 =
|
||||
@ -281,7 +288,10 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
|
||||
<Stack tokens={{ childrenGap: 4 }}>
|
||||
<Stack horizontal verticalAlign="center" tokens={{ childrenGap: 4 }}>
|
||||
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600,color: "var(--colorNeutralForeground1)" }}>
|
||||
<Text
|
||||
variant="small"
|
||||
style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}
|
||||
>
|
||||
Maximum RU/s
|
||||
</Text>
|
||||
<InfoTooltip>{getAutoScaleTooltip()}</InfoTooltip>
|
||||
@ -291,7 +301,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
type="number"
|
||||
styles={{
|
||||
fieldGroup: { width: 100, height: 27, flexShrink: 0 },
|
||||
field: { fontSize: 14, fontWeight: 400 , color: "var(--colorNeutralForeground1)"},
|
||||
field: { fontSize: 14, fontWeight: 400, color: "var(--colorNeutralForeground1)" },
|
||||
}}
|
||||
onChange={(_event, newInput?: string) => onThroughputValueChange(newInput)}
|
||||
step={AutoPilotUtils.autoPilotIncrementStep}
|
||||
@ -307,7 +317,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
|
||||
<CostEstimateText requestUnits={throughput} isAutoscale={isAutoscaleSelected} />
|
||||
<Stack className="throughputInputSpacing">
|
||||
<Text variant="small" aria-label="ruDescription" style={{color: "var(--colorNeutralForeground1)" }}>
|
||||
<Text variant="small" aria-label="ruDescription" style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||
Estimate your required RU/s with
|
||||
<Link
|
||||
className="underlinedLink"
|
||||
@ -326,7 +336,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
|
||||
{!isAutoscaleSelected && (
|
||||
<Stack className="throughputInputSpacing">
|
||||
<Text variant="small" aria-label="ruDescription" style={{color: "var(--colorNeutralForeground1)" }}>
|
||||
<Text variant="small" aria-label="ruDescription" style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||
Estimate your required RU/s with
|
||||
<Link
|
||||
className="underlinedLink"
|
||||
@ -339,7 +349,11 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
.
|
||||
</Text>
|
||||
<Stack horizontal>
|
||||
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }} aria-label="maxRUDescription">
|
||||
<Text
|
||||
variant="small"
|
||||
style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}
|
||||
aria-label="maxRUDescription"
|
||||
>
|
||||
{isDatabase ? "Database" : getCollectionName()} Required RU/s
|
||||
</Text>
|
||||
<InfoTooltip>{getAutoScaleTooltip()}</InfoTooltip>
|
||||
|
@ -1,8 +1,4 @@
|
||||
import {
|
||||
Button as FluentButton,
|
||||
makeStyles,
|
||||
tokens,
|
||||
} from "@fluentui/react-components";
|
||||
import { Button as FluentButton, makeStyles, tokens } from "@fluentui/react-components";
|
||||
import * as React from "react";
|
||||
|
||||
export type CustomButtonProps = {
|
||||
@ -39,21 +35,13 @@ const useStyles = makeStyles({
|
||||
},
|
||||
});
|
||||
|
||||
export const Button = React.forwardRef<HTMLButtonElement, CustomButtonProps>(
|
||||
({ primary, ...props }, ref) => {
|
||||
const baseStyles = useStyles();
|
||||
const buttonClassName = primary ? baseStyles.primary : baseStyles.button;
|
||||
export const Button = React.forwardRef<HTMLButtonElement, CustomButtonProps>(({ primary, ...props }, ref) => {
|
||||
const baseStyles = useStyles();
|
||||
const buttonClassName = primary ? baseStyles.primary : baseStyles.button;
|
||||
|
||||
return (
|
||||
<FluentButton
|
||||
{...props}
|
||||
ref={ref}
|
||||
appearance={primary ? "primary" : "secondary"}
|
||||
className={buttonClassName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
return (
|
||||
<FluentButton {...props} ref={ref} appearance={primary ? "primary" : "secondary"} className={buttonClassName} />
|
||||
);
|
||||
});
|
||||
|
||||
// Add display name
|
||||
Button.displayName = "Button";
|
||||
|
@ -15,7 +15,7 @@ const useStyles = makeStyles({
|
||||
},
|
||||
});
|
||||
|
||||
export const DataExplorer: React.FC<DataExplorerProps> = ({ dataExplorer }) => {
|
||||
export const DataExplorer: React.FC<DataExplorerProps> = () => {
|
||||
const styles = useStyles();
|
||||
|
||||
return (
|
||||
|
@ -73,11 +73,11 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
|
||||
const { targetDocument } = useFluent();
|
||||
const setKeyboardHandlers = useKeyboardActionGroup(KeyboardActionGroup.COMMAND_BAR);
|
||||
const styles = useStyles();
|
||||
|
||||
|
||||
const { connectionInfo, isPhoenixNotebooks, isPhoenixFeatures } = useNotebook((state) => ({
|
||||
connectionInfo: state.connectionInfo,
|
||||
isPhoenixNotebooks: state.isPhoenixNotebooks,
|
||||
isPhoenixFeatures: state.isPhoenixFeatures
|
||||
isPhoenixFeatures: state.isPhoenixFeatures,
|
||||
}));
|
||||
|
||||
if (userContext.apiType === "Postgres" || userContext.apiType === "VCoreMongo") {
|
||||
@ -126,10 +126,7 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
|
||||
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
|
||||
|
||||
// Add connection status if needed (using the hook values we got at the top level)
|
||||
if (
|
||||
(isPhoenixNotebooks || isPhoenixFeatures) &&
|
||||
connectionInfo?.status !== ConnectionStatusType.Connect
|
||||
) {
|
||||
if ((isPhoenixNotebooks || isPhoenixFeatures) && connectionInfo?.status !== ConnectionStatusType.Connect) {
|
||||
uiFabricControlButtons.unshift(
|
||||
CommandBarUtil.createConnectionStatus(container, PoolIdType.DefaultPoolId, "connectionStatus"),
|
||||
);
|
||||
@ -152,8 +149,8 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
|
||||
":active": {
|
||||
backgroundColor: "var(--colorNeutralBackground3)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
menuIcon: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
@ -165,7 +162,7 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
|
||||
link: {
|
||||
backgroundColor: "var(--colorNeutralBackground1)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const allButtons = staticButtons.concat(contextButtons).concat(controlButtons);
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { OpenFullScreen } from "Explorer/OpenFullScreen";
|
||||
import { KeyboardAction } from "KeyboardShortcuts";
|
||||
import { isDataplaneRbacSupported } from "Utils/APITypeUtils";
|
||||
import * as React from "react";
|
||||
@ -25,12 +26,12 @@ import { useSidePanel } from "../../../hooks/useSidePanel";
|
||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||
import Explorer from "../../Explorer";
|
||||
import { useNotebook } from "../../Notebook/useNotebook";
|
||||
import { OpenFullScreen } from "../../OpenFullScreen";
|
||||
import { BrowseQueriesPane } from "../../Panes/BrowseQueriesPane/BrowseQueriesPane";
|
||||
import { LoadQueryPane } from "../../Panes/LoadQueryPane/LoadQueryPane";
|
||||
import { SettingsPane, useDataPlaneRbac } from "../../Panes/SettingsPane/SettingsPane";
|
||||
import { useDatabases } from "../../useDatabases";
|
||||
import { SelectedNodeState, useSelectedNode } from "../../useSelectedNode";
|
||||
import { ThemeToggleButton } from "./ThemeToggleButton";
|
||||
|
||||
let counter = 0;
|
||||
|
||||
@ -175,6 +176,7 @@ export function createContextCommandBarButtons(
|
||||
|
||||
export function createControlCommandBarButtons(container: Explorer): CommandButtonComponentProps[] {
|
||||
const buttons: CommandButtonComponentProps[] = [
|
||||
ThemeToggleButton(),
|
||||
{
|
||||
iconSrc: SettingsIcon,
|
||||
iconAlt: "Settings",
|
||||
|
29
src/Explorer/Menus/CommandBar/ThemeToggleButton.tsx
Normal file
29
src/Explorer/Menus/CommandBar/ThemeToggleButton.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import * as React from "react";
|
||||
import MoonBlueIcon from "../../../../images/moon-blue.svg";
|
||||
import SunBlueIcon from "../../../../images/sun-blue.svg";
|
||||
import { useThemeStore } from "../../../hooks/useTheme";
|
||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||
|
||||
export const ThemeToggleButton = (): CommandButtonComponentProps => {
|
||||
const [darkMode, setDarkMode] = React.useState(useThemeStore.getState().isDarkMode);
|
||||
|
||||
React.useEffect(() => {
|
||||
const unsubscribe = useThemeStore.subscribe((state) => {
|
||||
setDarkMode(state.isDarkMode);
|
||||
});
|
||||
return unsubscribe;
|
||||
}, []);
|
||||
|
||||
const tooltipText = darkMode ? "Switch to Light Theme" : "Switch to Dark Theme";
|
||||
|
||||
return {
|
||||
iconSrc: darkMode ? SunBlueIcon : MoonBlueIcon,
|
||||
iconAlt: "Theme Toggle",
|
||||
onCommandClick: useThemeStore.getState().toggleTheme,
|
||||
commandButtonLabel: undefined,
|
||||
ariaLabel: tooltipText,
|
||||
tooltipText: tooltipText,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
};
|
||||
};
|
@ -6,7 +6,7 @@ export const OpenFullScreen: React.FunctionComponent = () => {
|
||||
<>
|
||||
<div style={{ padding: "34px" }}>
|
||||
<Stack tokens={{ childrenGap: 10 }}>
|
||||
<Text>
|
||||
<Text style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||
Open this database account in a new browser tab with Cosmos DB Explorer. You can connect using your
|
||||
Microsoft account or a connection string.
|
||||
</Text>
|
||||
|
@ -653,26 +653,26 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
{userContext.apiType === "SQL" && (
|
||||
<Stack className="panelGroupSpacing">
|
||||
<DefaultButton
|
||||
styles={{
|
||||
root: {
|
||||
padding: 0,
|
||||
width: 200,
|
||||
styles={{
|
||||
root: {
|
||||
padding: 0,
|
||||
width: 200,
|
||||
height: 30,
|
||||
backgroundColor: 'var(--colorNeutralBackground2)',
|
||||
color: 'var(--colorNeutralForeground1)',
|
||||
borderColor: 'var(--colorNeutralStroke1)'
|
||||
backgroundColor: "var(--colorNeutralBackground2)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
borderColor: "var(--colorNeutralStroke1)",
|
||||
},
|
||||
rootHovered: {
|
||||
backgroundColor: 'var(--colorNeutralBackground3)',
|
||||
color: 'var(--colorNeutralForeground1)',
|
||||
backgroundColor: "var(--colorNeutralBackground3)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
rootPressed: {
|
||||
backgroundColor: 'var(--colorBrandBackgroundPressed)',
|
||||
color: 'var(--colorNeutralForegroundOnBrand)',
|
||||
backgroundColor: "var(--colorBrandBackgroundPressed)",
|
||||
color: "var(--colorNeutralForegroundOnBrand)",
|
||||
},
|
||||
label: {
|
||||
fontSize: 12,
|
||||
},
|
||||
label: {
|
||||
fontSize: 12
|
||||
}
|
||||
}}
|
||||
hidden={this.state.useHashV1}
|
||||
disabled={this.state.subPartitionKeys.length >= Constants.BackendDefaults.maxNumMultiHashPartition}
|
||||
@ -707,9 +707,9 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
label: { padding: 0, alignItems: "center" },
|
||||
root: {
|
||||
selectors: {
|
||||
':hover .ms-Checkbox-text': { color: "var(--colorNeutralForeground1)" }
|
||||
}
|
||||
}
|
||||
":hover .ms-Checkbox-text": { color: "var(--colorNeutralForeground1)" },
|
||||
},
|
||||
},
|
||||
}}
|
||||
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
|
||||
this.setState({ enableDedicatedThroughput: isChecked })
|
||||
@ -798,7 +798,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
|
||||
<ActionButton
|
||||
iconProps={{ iconName: "Add" }}
|
||||
styles={{ root: { padding: 0 }, label: { fontSize: 12 , color: "var(--colorNeutralForeground1)"}}}
|
||||
styles={{ root: { padding: 0 }, label: { fontSize: 12, color: "var(--colorNeutralForeground1)" } }}
|
||||
onClick={() => this.setState({ uniqueKeys: [...this.state.uniqueKeys, ""] })}
|
||||
>
|
||||
Add unique key
|
||||
@ -969,9 +969,9 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
label: { padding: 0, alignItems: "center" },
|
||||
root: {
|
||||
selectors: {
|
||||
':hover .ms-Checkbox-text': { color: "var(--colorNeutralForeground1)" }
|
||||
}
|
||||
}
|
||||
":hover .ms-Checkbox-text": { color: "var(--colorNeutralForeground1)" },
|
||||
},
|
||||
},
|
||||
}}
|
||||
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
|
||||
this.setState({ createMongoWildCardIndex: isChecked })
|
||||
@ -991,9 +991,9 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
label: { padding: 0, alignItems: "center", wordWrap: "break-word", whiteSpace: "break-spaces" },
|
||||
root: {
|
||||
selectors: {
|
||||
':hover .ms-Checkbox-text': { color: "var(--colorNeutralForeground1)" }
|
||||
}
|
||||
}
|
||||
":hover .ms-Checkbox-text": { color: "var(--colorNeutralForeground1)" },
|
||||
},
|
||||
},
|
||||
}}
|
||||
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
|
||||
this.setState({ useHashV1: isChecked, subPartitionKeys: [] })
|
||||
|
@ -66,44 +66,43 @@ export class PanelContainerComponent extends React.Component<PanelContainerProps
|
||||
onRenderNavigationContent={this.props.onRenderNavigationContent}
|
||||
isFooterAtBottom={true}
|
||||
styles={{
|
||||
navigation: {
|
||||
navigation: {
|
||||
borderBottom: "1px solid var(--colorNeutralStroke1)",
|
||||
backgroundColor: "var(--colorNeutralBackground1)",
|
||||
color: "var(--colorNeutralForeground1)"
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
content: {
|
||||
content: {
|
||||
padding: 0,
|
||||
backgroundColor: "var(--colorNeutralBackground1)",
|
||||
color: "var(--colorNeutralForeground1)"
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
header: {
|
||||
header: {
|
||||
padding: "0 0 8px 34px",
|
||||
backgroundColor: "var(--colorNeutralBackground1)",
|
||||
color: "var(--colorNeutralForeground1)"
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
commands: {
|
||||
marginTop: 8,
|
||||
commands: {
|
||||
marginTop: 8,
|
||||
paddingTop: 0,
|
||||
backgroundColor: "var(--colorNeutralBackground1)"
|
||||
},
|
||||
root: {
|
||||
backgroundColor: "var(--colorNeutralBackground1)",
|
||||
},
|
||||
root: {},
|
||||
overlay: {
|
||||
backgroundColor: "var(--overlayBackground)"
|
||||
backgroundColor: "var(--overlayBackground)",
|
||||
},
|
||||
main: {
|
||||
backgroundColor: "var(--colorNeutralBackground1)"
|
||||
backgroundColor: "var(--colorNeutralBackground1)",
|
||||
},
|
||||
scrollableContent: {
|
||||
backgroundColor: "var(--colorNeutralBackground1)"
|
||||
backgroundColor: "var(--colorNeutralBackground1)",
|
||||
},
|
||||
footerInner: {
|
||||
backgroundColor: "var(--colorNeutralBackground1)",
|
||||
color: "var(--colorNeutralForeground1)"
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
closeButton: {
|
||||
color: "var(--colorNeutralForeground1)"
|
||||
}
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
}}
|
||||
style={{ height: this.state.height }}
|
||||
>
|
||||
|
@ -54,31 +54,6 @@ import React, { FunctionComponent, useState } from "react";
|
||||
import create, { UseStore } from "zustand";
|
||||
import Explorer from "../../Explorer";
|
||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||
|
||||
// Not currently used, but keeping for future reference
|
||||
|
||||
/*
|
||||
const spinButtonStyles: ISpinButtonStyles = {
|
||||
label: {
|
||||
fontSize: 12,
|
||||
fontWeight: 400,
|
||||
color: "inherit",
|
||||
},
|
||||
root: {
|
||||
paddingBottom: 10,
|
||||
},
|
||||
labelWrapper: {
|
||||
color: "inherit",
|
||||
},
|
||||
icon: {},
|
||||
spinButtonWrapper: {},
|
||||
input: {
|
||||
color: "inherit",
|
||||
},
|
||||
arrowButtonsContainer: {},
|
||||
};
|
||||
*/
|
||||
|
||||
export interface DataPlaneRbacState {
|
||||
dataPlaneRbacEnabled: boolean;
|
||||
aadTokenUpdated: boolean;
|
||||
@ -187,9 +162,9 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
||||
globalAccountName: userContext.databaseAccount?.name,
|
||||
})
|
||||
? (loadState({
|
||||
componentName: AppStateComponentNames.SelectedRegionalEndpoint,
|
||||
globalAccountName: userContext.databaseAccount?.name,
|
||||
}) as string)
|
||||
componentName: AppStateComponentNames.SelectedRegionalEndpoint,
|
||||
globalAccountName: userContext.databaseAccount?.name,
|
||||
}) as string)
|
||||
: undefined,
|
||||
);
|
||||
const [retryAttempts, setRetryAttempts] = useState<number>(
|
||||
@ -1049,6 +1024,11 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
||||
checked={containerPaginationEnabled}
|
||||
onChange={() => setContainerPaginationEnabled(!containerPaginationEnabled)}
|
||||
label="Enable container pagination"
|
||||
onRenderLabel={() => (
|
||||
<span style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||
Enable container pagination
|
||||
</span>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</AccordionPanel>
|
||||
@ -1073,7 +1053,11 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
||||
ariaLabel="Enable cross partition query"
|
||||
checked={crossPartitionQueryEnabled}
|
||||
onChange={() => setCrossPartitionQueryEnabled(!crossPartitionQueryEnabled)}
|
||||
label="Enable cross-partition query"
|
||||
onRenderLabel={() => (
|
||||
<span style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||
Enable cross-partition query
|
||||
</span>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</AccordionPanel>
|
||||
@ -1105,7 +1089,11 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
||||
ariaLabel="EnableQueryControl"
|
||||
checked={queryControlEnabled}
|
||||
onChange={() => setQueryControlEnabled(!queryControlEnabled)}
|
||||
label="Enable query control"
|
||||
onRenderLabel={() => (
|
||||
<span style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||
Enable query control
|
||||
</span>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</AccordionPanel>
|
||||
@ -1139,6 +1127,11 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
||||
onValidate={(newValue) => setMaxDegreeOfParallelism(parseInt(newValue) || maxDegreeOfParallelism)}
|
||||
ariaLabel="Max degree of parallelism"
|
||||
label="Max degree of parallelism"
|
||||
styles={{
|
||||
label: {
|
||||
color: "var(--colorNeutralForeground1)"
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</AccordionPanel>
|
||||
@ -1208,7 +1201,11 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
||||
ariaLabel="Enable sample db for query exploration"
|
||||
checked={copilotSampleDBEnabled}
|
||||
onChange={handleSampleDatabaseChange}
|
||||
label="Enable sample database"
|
||||
onRenderLabel={() => (
|
||||
<span style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||
Enable sample database
|
||||
</span>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</AccordionPanel>
|
||||
@ -1248,12 +1245,12 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
||||
selectors: {
|
||||
":hover": {
|
||||
backgroundColor: "var(--colorBrandBackgroundHover)",
|
||||
color: "var(--colorNeutralForegroundOnBrand)"
|
||||
color: "var(--colorNeutralForegroundOnBrand)",
|
||||
},
|
||||
":active": {
|
||||
backgroundColor: "var(--colorBrandBackgroundPressed)",
|
||||
color: "var(--colorNeutralForegroundOnBrand)"
|
||||
}
|
||||
color: "var(--colorNeutralForegroundOnBrand)",
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
|
@ -1,30 +1,5 @@
|
||||
// @import "../../../less/Common/Constants";
|
||||
|
||||
// .splashScreenContainer {
|
||||
// width: 100%;
|
||||
// overflow-y: scroll;
|
||||
// overflow-x: hidden;
|
||||
|
||||
// .splashScreen {
|
||||
// .flex-display();
|
||||
// .flex-direction();
|
||||
// text-align: left;
|
||||
// margin: auto;
|
||||
// padding-left: 21px;
|
||||
// padding-right: 16px;
|
||||
// max-width: 1168px;
|
||||
|
||||
// > .title {
|
||||
// position: relative; // To attach FeaturePanelLauncher as absolute
|
||||
// color: @BaseHigh;
|
||||
// font-size: 48px;
|
||||
// padding-left: 0px;
|
||||
// margin: 16px auto;
|
||||
// text-align: center;
|
||||
// }
|
||||
|
||||
> .subtitle {
|
||||
// color: @BaseHigh;
|
||||
font-size: 18px;
|
||||
padding-left: 0px;
|
||||
margin: 0px auto;
|
||||
@ -46,148 +21,3 @@
|
||||
}
|
||||
}
|
||||
|
||||
// .mainButtonsContainer {
|
||||
// .flex-display();
|
||||
// text-align: center;
|
||||
// cursor: pointer;
|
||||
// margin: 40px auto;
|
||||
// width: 84%;
|
||||
|
||||
// > .mainButton {
|
||||
// min-width: 124px;
|
||||
// max-width: 296px;
|
||||
// padding: 32px 16px;
|
||||
// background-color: @BaseLight;
|
||||
// border: 1px solid #949494;
|
||||
// box-sizing: border-box;
|
||||
// box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
|
||||
// border-radius: 4px;
|
||||
|
||||
// > .legendContainer {
|
||||
// margin-left: 16px;
|
||||
// text-align: left;
|
||||
|
||||
// .legend {
|
||||
// font-family: @SemiboldFont;
|
||||
// font-size: 18px;
|
||||
// }
|
||||
|
||||
// .description {
|
||||
// font-size: 10px;
|
||||
// }
|
||||
|
||||
// .newDescription {
|
||||
// font-size: 13px;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// > :nth-child(n + 2) {
|
||||
// margin-left: 32px;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .moreStuffContainer {
|
||||
// .flex-display();
|
||||
// justify-content: space-between;
|
||||
|
||||
// .moreStuffColumn {
|
||||
// flex-grow: 1;
|
||||
// flex-basis: 0;
|
||||
// min-width: 124px;
|
||||
// max-width: 296px;
|
||||
|
||||
// > .title {
|
||||
// font-size: 18px;
|
||||
// font-family: @SemiboldFont;
|
||||
// color: @BaseDark;
|
||||
// padding: 0px;
|
||||
// margin-bottom: 16px;
|
||||
// }
|
||||
|
||||
// > ul {
|
||||
// list-style: none;
|
||||
// padding-left: 0px;
|
||||
// margin-bottom: 0px;
|
||||
|
||||
// li {
|
||||
// padding: @DefaultSpace;
|
||||
// .flex-display();
|
||||
// align-items: flex-start;
|
||||
|
||||
// > img {
|
||||
// margin-right: @DefaultSpace;
|
||||
// width: 24px;
|
||||
// height: 24px;
|
||||
// }
|
||||
|
||||
// .oneLineContent {
|
||||
// margin-top: 4px;
|
||||
// }
|
||||
|
||||
// .description {
|
||||
// font-size: 10px;
|
||||
// color: @BaseMediumHigh;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// .tipContainer {
|
||||
// padding: 8px 16px;
|
||||
// width: 100%;
|
||||
// cursor: pointer;
|
||||
// .flex-display();
|
||||
// .flex-direction();
|
||||
|
||||
// > .title {
|
||||
// color: @BaseDark;
|
||||
// padding: 0px;
|
||||
// font-size: 12px;
|
||||
// }
|
||||
// > .description {
|
||||
// color: @BaseDark;
|
||||
// }
|
||||
|
||||
// &:not(:hover):not(:focus) {
|
||||
// background-color: @BaseLow;
|
||||
// }
|
||||
// }
|
||||
|
||||
// &.commonTasks {
|
||||
// li {
|
||||
// cursor: pointer;
|
||||
// }
|
||||
// }
|
||||
|
||||
// &.tipsContainer {
|
||||
// li {
|
||||
// margin: 2px 0px;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// .focusable {
|
||||
// &:hover {
|
||||
// .hover();
|
||||
// }
|
||||
|
||||
// &:focus {
|
||||
// .focus();
|
||||
// }
|
||||
|
||||
// &:active {
|
||||
// .active();
|
||||
// }
|
||||
// }
|
||||
|
||||
// .notebookSplashScreenItem {
|
||||
// padding: 12px 0 12px 12px;
|
||||
|
||||
// .itemText {
|
||||
// margin-left: 12px;
|
||||
// font-family: @SemiboldFont;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
@ -35,7 +35,6 @@ import CollectionIcon from "../../../images/tree-collection.svg";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import { userContext } from "../../UserContext";
|
||||
import { getCollectionName } from "../../Utils/APITypeUtils";
|
||||
import { useTheme } from "../../hooks/useTheme";
|
||||
import Explorer from "../Explorer";
|
||||
import * as MostRecentActivity from "../MostRecentActivity/MostRecentActivity";
|
||||
import { useNotebook } from "../Notebook/useNotebook";
|
||||
@ -61,18 +60,15 @@ const useStyles = makeStyles({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
// justifyContent: "center",
|
||||
minHeight: "100vh",
|
||||
backgroundColor: "var(--colorNeutralBackground1)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
splashScreen: {
|
||||
display: "flex",
|
||||
// overflow: "scroll",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
textAlign: "left",
|
||||
// ...shorthands.padding("40px")
|
||||
},
|
||||
title: {
|
||||
fontSize: "48px",
|
||||
@ -140,7 +136,6 @@ const useStyles = makeStyles({
|
||||
moreStuffColumn: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
// justifyContent:"space-between"
|
||||
},
|
||||
columnTitle: {
|
||||
fontSize: "20px",
|
||||
@ -166,9 +161,6 @@ const useStyles = makeStyles({
|
||||
|
||||
export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
|
||||
const styles = useStyles();
|
||||
// isDarkMode is used for conditional styling in the component
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { isDarkMode } = useTheme();
|
||||
const container = explorer;
|
||||
const subscriptions: Array<{ dispose: () => void }> = [];
|
||||
|
||||
|
@ -24,7 +24,7 @@ import { Allotment } from "allotment";
|
||||
import { useClientWriteEnabled } from "hooks/useClientWriteEnabled";
|
||||
import { QueryCopilotState, useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import { TabsState, useTabs } from "hooks/useTabs";
|
||||
import { monacoTheme } from "hooks/useTheme";
|
||||
import { useMonacoTheme } from "hooks/useTheme";
|
||||
import React, { Fragment, createRef } from "react";
|
||||
import "react-splitter-layout/lib/index.css";
|
||||
import { format } from "react-string-format";
|
||||
@ -126,6 +126,7 @@ interface IQueryTabStates {
|
||||
|
||||
export const QueryTabCopilotComponent = (props: IQueryTabComponentProps): any => {
|
||||
const styles = useQueryTabStyles();
|
||||
const monacoTheme = useMonacoTheme();
|
||||
const copilotStore = useCopilotStore();
|
||||
|
||||
const isSampleCopilotActive = useSelectedNode.getState().isQueryCopilotCollectionSelected();
|
||||
@ -137,16 +138,18 @@ export const QueryTabCopilotComponent = (props: IQueryTabComponentProps): any =>
|
||||
isSampleCopilotActive: isSampleCopilotActive,
|
||||
copilotStore: copilotStore,
|
||||
};
|
||||
return <QueryTabComponentImpl styles={styles} {...queryTabProps} />;
|
||||
return <QueryTabComponentImpl styles={styles} monacoTheme={monacoTheme} {...queryTabProps} />;
|
||||
};
|
||||
|
||||
export const QueryTabComponent = (props: IQueryTabComponentProps): any => {
|
||||
const styles = useQueryTabStyles();
|
||||
return <QueryTabComponentImpl styles={styles} {...{ ...props }} />;
|
||||
const monacoTheme = useMonacoTheme();
|
||||
return <QueryTabComponentImpl styles={styles} monacoTheme={monacoTheme} {...{ ...props }} />;
|
||||
};
|
||||
|
||||
type QueryTabComponentImplProps = IQueryTabComponentProps & {
|
||||
styles: QueryTabStyles;
|
||||
monacoTheme: string;
|
||||
};
|
||||
|
||||
// Inner (legacy) class component. We only use this component via one of the two functional components above (since we need to use the `useQueryTabStyles` hook).
|
||||
@ -761,7 +764,7 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
|
||||
wordWrap={"on"}
|
||||
ariaLabel={"Editing Query"}
|
||||
lineNumbers={"on"}
|
||||
theme={monacoTheme}
|
||||
theme={this.props.monacoTheme}
|
||||
onContentChanged={(newContent: string) => this.onChangeContent(newContent)}
|
||||
onContentSelected={(selectedContent: string, selection: monaco.Selection) =>
|
||||
this.onSelectedContent(selectedContent, selection)
|
||||
|
@ -3,7 +3,7 @@ import { Label, TextField } from "@fluentui/react";
|
||||
import { FluentProvider, webDarkTheme, webLightTheme } from "@fluentui/react-components";
|
||||
import { KeyboardAction } from "KeyboardShortcuts";
|
||||
import { ValidCosmosDbIdDescription, ValidCosmosDbIdInputPattern } from "Utils/ValidationUtils";
|
||||
import { isDarkMode } from "hooks/useTheme";
|
||||
import { useThemeStore } from "hooks/useTheme";
|
||||
import React, { Component } from "react";
|
||||
import DiscardIcon from "../../../images/discard.svg";
|
||||
import SaveIcon from "../../../images/save-cosmos.svg";
|
||||
@ -259,7 +259,7 @@ export default class UserDefinedFunctionTabContent extends Component<
|
||||
|
||||
render(): JSX.Element {
|
||||
const { udfId, udfBody, isUdfIdEditable } = this.state;
|
||||
const currentTheme = isDarkMode ? webDarkTheme : webLightTheme;
|
||||
const currentTheme = useThemeStore.getState().isDarkMode ? webDarkTheme : webLightTheme;
|
||||
return (
|
||||
<div className="tab-pane flexContainer trigger-form" role="tabpanel">
|
||||
<FluentProvider theme={currentTheme}>
|
||||
|
13
src/Main.tsx
13
src/Main.tsx
@ -63,7 +63,7 @@ import { appThemeFabric } from "./Platform/Fabric/FabricTheme";
|
||||
import "./Shared/appInsights";
|
||||
import { useConfig } from "./hooks/useConfig";
|
||||
import { useKnockoutExplorer } from "./hooks/useKnockoutExplorer";
|
||||
import { isDarkMode } from "./hooks/useTheme";
|
||||
import { useThemeStore } from "./hooks/useTheme";
|
||||
import "./less/DarkModeMenus.less";
|
||||
import "./less/ThemeSystem.less";
|
||||
// Initialize icons before React is loaded
|
||||
@ -153,7 +153,18 @@ const App = (): JSX.Element => {
|
||||
};
|
||||
|
||||
const Root: React.FC = () => {
|
||||
// Use React state to track isDarkMode and subscribe to changes
|
||||
const [isDarkMode, setIsDarkMode] = React.useState(useThemeStore.getState().isDarkMode);
|
||||
const currentTheme = isDarkMode ? webDarkTheme : webLightTheme;
|
||||
|
||||
// Subscribe to theme changes
|
||||
React.useEffect(() => {
|
||||
return useThemeStore.subscribe(
|
||||
(state) => {
|
||||
setIsDarkMode(state.isDarkMode);
|
||||
}
|
||||
);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDarkMode) {
|
||||
|
@ -1,5 +1,30 @@
|
||||
import { useFluent } from "@fluentui/react-components";
|
||||
import React, { createContext, FC, ReactNode, useEffect, useState } from "react";
|
||||
import create from "zustand";
|
||||
|
||||
interface ThemeSettings {
|
||||
mode: number;
|
||||
}
|
||||
|
||||
interface FxsTheme {
|
||||
(): ThemeSettings;
|
||||
subscribe: (context: null, callback: (update: ThemeSettings) => void) => void;
|
||||
}
|
||||
|
||||
interface MsPortalFxSettings {
|
||||
"fxs-theme"?: FxsTheme;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
MsPortalFx?: {
|
||||
Services: {
|
||||
getSettings: () => Promise<MsPortalFxSettings>;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
interface ThemeContextType {
|
||||
theme: "Light" | "Dark";
|
||||
@ -17,19 +42,129 @@ export const CustomThemeProvider: FC<ThemeProviderProps> = ({ children, theme })
|
||||
const isDarkMode = theme === "Dark";
|
||||
return <ThemeContext.Provider value={{ theme, isDarkMode }}>{children}</ThemeContext.Provider>;
|
||||
};
|
||||
export const isDarkMode = true;
|
||||
export const monacoTheme = isDarkMode ? "vs-dark" : "vs";
|
||||
|
||||
export interface ThemeStore {
|
||||
isDarkMode: boolean;
|
||||
themeMode: number;
|
||||
toggleTheme: () => void;
|
||||
}
|
||||
|
||||
export const useThemeStore = create<ThemeStore>((set) => ({
|
||||
isDarkMode: false,
|
||||
themeMode: 0,
|
||||
toggleTheme: () =>
|
||||
set((state) => {
|
||||
const newIsDarkMode = !state.isDarkMode;
|
||||
const newThemeMode = newIsDarkMode ? 1 : 0;
|
||||
|
||||
if (newIsDarkMode) {
|
||||
document.body.classList.add("isDarkMode");
|
||||
} else {
|
||||
document.body.classList.remove("isDarkMode");
|
||||
}
|
||||
|
||||
// Save to localStorage for persistence
|
||||
localStorage.setItem("cosmos-explorer-theme", newIsDarkMode ? "dark" : "light");
|
||||
localStorage.setItem("cosmos-explorer-theme-mode", String(newThemeMode));
|
||||
|
||||
return {
|
||||
isDarkMode: newIsDarkMode,
|
||||
themeMode: newThemeMode,
|
||||
};
|
||||
}),
|
||||
}));
|
||||
|
||||
// Initialize the theme from localStorage or MsPortalFx if available
|
||||
if (typeof window !== "undefined") {
|
||||
// Try to initialize from MsPortalFx.Services if available
|
||||
try {
|
||||
if (window.MsPortalFx && window.MsPortalFx.Services) {
|
||||
window.MsPortalFx.Services.getSettings()
|
||||
.then((settings: MsPortalFxSettings) => {
|
||||
if (settings["fxs-theme"]) {
|
||||
const theme = settings["fxs-theme"];
|
||||
|
||||
// Initial theme value
|
||||
const initialTheme = theme();
|
||||
if (initialTheme && typeof initialTheme.mode === "number") {
|
||||
const isDark = initialTheme.mode === 1;
|
||||
useThemeStore.setState({
|
||||
isDarkMode: isDark,
|
||||
themeMode: initialTheme.mode,
|
||||
});
|
||||
|
||||
if (isDark) {
|
||||
document.body.classList.add("isDarkMode");
|
||||
} else {
|
||||
document.body.classList.remove("isDarkMode");
|
||||
}
|
||||
}
|
||||
|
||||
theme.subscribe(null, (themeUpdate: ThemeSettings) => {
|
||||
if (themeUpdate && typeof themeUpdate.mode === "number") {
|
||||
const isDark = themeUpdate.mode === 1;
|
||||
useThemeStore.setState({
|
||||
isDarkMode: isDark,
|
||||
themeMode: themeUpdate.mode,
|
||||
});
|
||||
|
||||
if (isDark) {
|
||||
document.body.classList.add("isDarkMode");
|
||||
} else {
|
||||
document.body.classList.remove("isDarkMode");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
fallbackToLocalStorage();
|
||||
});
|
||||
} else {
|
||||
fallbackToLocalStorage();
|
||||
}
|
||||
} catch (error) {
|
||||
fallbackToLocalStorage();
|
||||
}
|
||||
}
|
||||
|
||||
function fallbackToLocalStorage() {
|
||||
const savedTheme = localStorage.getItem("cosmos-explorer-theme");
|
||||
const savedThemeMode = localStorage.getItem("cosmos-explorer-theme-mode");
|
||||
|
||||
if (savedTheme || savedThemeMode) {
|
||||
const isDark = savedTheme === "dark" || savedThemeMode === "1";
|
||||
const themeMode = isDark ? 1 : 0;
|
||||
|
||||
useThemeStore.setState({
|
||||
isDarkMode: isDark,
|
||||
themeMode: themeMode,
|
||||
});
|
||||
|
||||
if (isDark) {
|
||||
document.body.classList.add("isDarkMode");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic exports that use the theme store
|
||||
export const isDarkMode = () => useThemeStore.getState().isDarkMode;
|
||||
|
||||
export const useMonacoTheme = () => {
|
||||
const { isDarkMode } = useThemeStore();
|
||||
return isDarkMode ? "vs-dark" : "vs";
|
||||
};
|
||||
|
||||
export const monacoTheme = () => (useThemeStore.getState().isDarkMode ? "vs-dark" : "vs");
|
||||
|
||||
export const useTheme = () => {
|
||||
const { targetDocument } = useFluent();
|
||||
const context = React.useContext(ThemeContext);
|
||||
|
||||
const [isDarkMode, setIsDarkMode] = useState(() => {
|
||||
// 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;
|
||||
});
|
||||
|
||||
@ -38,20 +173,16 @@ export const useTheme = () => {
|
||||
return undefined;
|
||||
}
|
||||
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);
|
||||
};
|
||||
|
||||
// Initial check
|
||||
checkTheme();
|
||||
|
||||
// Create a MutationObserver to watch for class changes
|
||||
const observer = new MutationObserver(() => {
|
||||
checkTheme();
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user