From f83b57673c6cf8303a13bf7e71e061563ffe4545 Mon Sep 17 00:00:00 2001
From: david qiu
Date: Tue, 23 Jan 2024 15:38:33 -0800
Subject: [PATCH] Backport PR #575: Reflect theme changes without a refresh
(#599)
* Reflect theme changes without a refresh
By leveraging `IThemeManager.themeChanged`, we can listen on theme change signals
and rebuild the theme object in response. This allows CSS variable changes to reflect
in the MUI theme without having to refresh the page.
* update yarn.lock
* pass themeManager as a prop instead of using top-level scope
* remove theme hack added in #192
---------
Co-authored-by: gchow
Co-authored-by: David L. Qiu
(cherry picked from commit ca03e2c9a846344c379d50ccbe8323f7e0c7b1ed)
Co-authored-by: Garson R Chow <58149459+garsonbyte@users.noreply.github.com>
---
packages/jupyter-ai/src/components/chat.tsx | 4 +++-
.../src/components/jl-theme-provider.tsx | 6 +++++-
packages/jupyter-ai/src/index.ts | 16 +++++++++++-----
packages/jupyter-ai/src/theme-provider.ts | 8 +-------
packages/jupyter-ai/src/widgets/chat-error.tsx | 9 ++++++---
packages/jupyter-ai/src/widgets/chat-sidebar.tsx | 5 ++++-
6 files changed, 30 insertions(+), 18 deletions(-)
diff --git a/packages/jupyter-ai/src/components/chat.tsx b/packages/jupyter-ai/src/components/chat.tsx
index ded339c70..53ba45f1a 100644
--- a/packages/jupyter-ai/src/components/chat.tsx
+++ b/packages/jupyter-ai/src/components/chat.tsx
@@ -4,6 +4,7 @@ import { Button, IconButton, Stack } from '@mui/material';
import SettingsIcon from '@mui/icons-material/Settings';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import type { Awareness } from 'y-protocols/awareness';
+import type { IThemeManager } from '@jupyterlab/apputils';
import { JlThemeProvider } from './jl-theme-provider';
import { ChatMessages } from './chat-messages';
@@ -178,6 +179,7 @@ export type ChatProps = {
selectionWatcher: SelectionWatcher;
chatHandler: ChatHandler;
globalAwareness: Awareness | null;
+ themeManager: IThemeManager | null;
chatView?: ChatView;
};
@@ -190,7 +192,7 @@ export function Chat(props: ChatProps): JSX.Element {
const [view, setView] = useState(props.chatView || ChatView.Chat);
return (
-
+
(createTheme());
@@ -12,7 +14,9 @@ export function JlThemeProvider(props: {
async function setJlTheme() {
setTheme(await getJupyterLabTheme());
}
+
setJlTheme();
+ props.themeManager?.themeChanged.connect(setJlTheme);
}, []);
return {props.children};
diff --git a/packages/jupyter-ai/src/index.ts b/packages/jupyter-ai/src/index.ts
index aefdc8e18..00d493289 100644
--- a/packages/jupyter-ai/src/index.ts
+++ b/packages/jupyter-ai/src/index.ts
@@ -4,7 +4,11 @@ import {
ILayoutRestorer
} from '@jupyterlab/application';
-import { IWidgetTracker, ReactWidget } from '@jupyterlab/apputils';
+import {
+ IWidgetTracker,
+ ReactWidget,
+ IThemeManager
+} from '@jupyterlab/apputils';
import { IDocumentWidget } from '@jupyterlab/docregistry';
import { IGlobalAwareness } from '@jupyterlab/collaboration';
import type { Awareness } from 'y-protocols/awareness';
@@ -21,11 +25,12 @@ export type DocumentTracker = IWidgetTracker;
const plugin: JupyterFrontEndPlugin = {
id: 'jupyter_ai:plugin',
autoStart: true,
- optional: [IGlobalAwareness, ILayoutRestorer],
+ optional: [IGlobalAwareness, ILayoutRestorer, IThemeManager],
activate: async (
app: JupyterFrontEnd,
globalAwareness: Awareness | null,
- restorer: ILayoutRestorer
+ restorer: ILayoutRestorer | null,
+ themeManager: IThemeManager | null
) => {
/**
* Initialize selection watcher singleton
@@ -43,10 +48,11 @@ const plugin: JupyterFrontEndPlugin = {
chatWidget = buildChatSidebar(
selectionWatcher,
chatHandler,
- globalAwareness
+ globalAwareness,
+ themeManager
);
} catch (e) {
- chatWidget = buildErrorWidget();
+ chatWidget = buildErrorWidget(themeManager);
}
/**
diff --git a/packages/jupyter-ai/src/theme-provider.ts b/packages/jupyter-ai/src/theme-provider.ts
index 405f08198..02db8d369 100644
--- a/packages/jupyter-ai/src/theme-provider.ts
+++ b/packages/jupyter-ai/src/theme-provider.ts
@@ -13,7 +13,6 @@ export async function pollUntilReady(): Promise {
export async function getJupyterLabTheme(): Promise {
await pollUntilReady();
const light = document.body.getAttribute('data-jp-theme-light');
- const primaryFontColor = getCSSVariable('--jp-ui-font-color1');
return createTheme({
spacing: 4,
components: {
@@ -113,7 +112,7 @@ export async function getJupyterLabTheme(): Promise {
dark: getCSSVariable('--jp-success-color0')
},
text: {
- primary: primaryFontColor,
+ primary: getCSSVariable('--jp-ui-font-color1'),
secondary: getCSSVariable('--jp-ui-font-color2'),
disabled: getCSSVariable('--jp-ui-font-color3')
}
@@ -127,11 +126,6 @@ export async function getJupyterLabTheme(): Promise {
htmlFontSize: 16,
button: {
textTransform: 'capitalize'
- },
- // this is undocumented as of the time of writing.
- // https://stackoverflow.com/a/62950304/12548458
- allVariants: {
- color: primaryFontColor
}
}
});
diff --git a/packages/jupyter-ai/src/widgets/chat-error.tsx b/packages/jupyter-ai/src/widgets/chat-error.tsx
index 3b8f8ef95..8ae9cbb44 100644
--- a/packages/jupyter-ai/src/widgets/chat-error.tsx
+++ b/packages/jupyter-ai/src/widgets/chat-error.tsx
@@ -1,13 +1,16 @@
import React from 'react';
import { ReactWidget } from '@jupyterlab/apputils';
+import type { IThemeManager } from '@jupyterlab/apputils';
+import { Alert, Box } from '@mui/material';
import { chatIcon } from '../icons';
-import { Alert, Box } from '@mui/material';
import { JlThemeProvider } from '../components/jl-theme-provider';
-export function buildErrorWidget(): ReactWidget {
+export function buildErrorWidget(
+ themeManager: IThemeManager | null
+): ReactWidget {
const ErrorWidget = ReactWidget.create(
-
+
);
ChatWidget.id = 'jupyter-ai::chat';