Skip to content

Commit 5d502cc

Browse files
theneelshahNeel Shah
andauthored
Theme support for Graph Notebook Widgets (#754)
* Add css variables from the Jupyter theme to be used for styling widget * Create css variables based on Jupyter Labs' theme + Read the Jupyter Labs' css variables and give custom variable names. + Provide fallback values incase css variables not present or for backward compatibility. + Apply updated styles explicitly for custom SVG icons. Tests: + The variables are applied to the global CSS. + The icons changes stroke color when theme is changed. * Use the theme variables + Make the custom widget use the Jupyter Labs' theme variables Tests: + The css for the widgets gets updated on theme change * Fix typo --------- Co-authored-by: Neel Shah <neeljs@amazon.com>
1 parent 094800b commit 5d502cc

File tree

4 files changed

+121
-27
lines changed

4 files changed

+121
-27
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Theme variables for graph-notebook
3+
*
4+
* Define custom CSS variables from the JupyterLabs' theme
5+
*/
6+
7+
:root {
8+
/* Base colors */
9+
--bg-primary: var(--jp-layout-color1, white);
10+
--bg-secondary: var(--jp-layout-color2, #f4f4f4);
11+
--font-color: var(--jp-content-font-color1, black);
12+
--border-color: var(--jp-border-color1, lightgrey);
13+
--shadow-color: var(--jp-shadow-base-color, grey);
14+
15+
/* Interactive elements */
16+
--accent-color: var(--jp-brand-color1, #4c6b9e);
17+
--accent-text-color: var(--jp-ui-inverse-font-color1, white);
18+
19+
/* Table colors */
20+
--table-row-odd: var(--jp-layout-color2, #f4f4f4);
21+
--table-row-even: var(--jp-layout-color1, white);
22+
23+
/* Menu icon stroke */
24+
--icon-stroke: black;
25+
}
26+
27+
body.jp-mod-dark,
28+
body[data-jp-theme-name="JupyterLab Dark"] {
29+
--icon-stroke: white;
30+
}

src/graph_notebook/widgets/css/widget.css

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@import './theme-variables.css';
2+
13
.menu-div {
24
position: absolute;
35
top: 5px;
@@ -17,18 +19,18 @@ svg {
1719

1820

1921
.menu-action > button {
20-
background: white;
22+
background: var(--bg-primary);
2123
width: 35px;
2224
height: 35px;
23-
border: 1px solid gray;
25+
border: 1px solid var(--border-color);
2426
border-radius: 2px;
2527
pointer-events: all;
2628
top: 0;
2729
position: center;
2830
}
2931

3032
.menu-action {
31-
background: white;
33+
background: var(--bg-primary);
3234
border: none;
3335
border-radius: 2px;
3436
display: inline;
@@ -37,7 +39,7 @@ svg {
3739
}
3840

3941
.fullscreen {
40-
background: white;
42+
background: var(--bg-primary);
4143
position: fixed;
4244
top: 0;
4345
bottom: 0;
@@ -82,12 +84,12 @@ svg {
8284
}
8385

8486
::backdrop {
85-
background-color: white;
87+
background-color: var(--bg-primary);
8688
}
8789

8890
.details {
8991
position: absolute !important;
90-
background-color: white;
92+
background-color: var(--bg-primary);
9193
text-align: center;
9294
border: none;
9395
visibility: visible;
@@ -97,14 +99,13 @@ svg {
9799
top: 100px;
98100
left: 100px;
99101
display: flex;
100-
101-
box-shadow: 3px 3px 3px 3px grey;
102+
box-shadow: 3px 3px 3px 3px var(--shadow-color);
102103
overflow: hidden;
104+
color: var(--font-color);
103105
}
104106

105107
.active {
106-
background-color: lightgrey !important;
107-
108+
background-color: var(--bg-secondary) !important;
108109
-webkit-transition: all .5s;
109110
-moz-transition: all .5s;
110111
-o-transition: all .5s;
@@ -119,10 +120,11 @@ td, th {
119120
border: none;
120121
text-align: left;
121122
padding: 8px;
123+
color: var(--font-color);
122124
}
123125

124126
tr:nth-child(odd) {
125-
background-color: #f4f4f4;
127+
background-color: var(--table-row-odd);
126128
}
127129

128130
.collapsible {
@@ -163,14 +165,14 @@ tr:nth-child(odd) {
163165
.properties-content {
164166
border: none;
165167
transition: max-height 0.2s ease-out;
166-
background-color: white;
168+
background-color: var(--bg-primary);
167169
height: calc(100% - 80px);
168170
overflow: scroll;
171+
color: var(--font-color);
169172
}
170173

171174
.displayNone {
172175
display: none !important;
173-
174176
width: 0;
175177
}
176178

@@ -186,10 +188,13 @@ tr:nth-child(odd) {
186188
margin: auto auto auto 10px;
187189
overflow: hidden;
188190
width: 100%;
191+
color: var(--font-color);
189192
}
190193

191194
.details-container {
192195
width: 100%;
196+
background-color: var(--bg-primary);
197+
color: var(--font-color);
193198
}
194199

195200
div.menu-action.active::after {
@@ -205,10 +210,10 @@ div.menu-action.active::after {
205210
}
206211

207212
.vis-tooltip {
208-
background: white !important;
213+
background: var(--bg-primary) !important;
209214
font-size: 1em !important;
210215
font-family: "Courier New", Courier, monospace !important;
211-
216+
color: var(--font-color) !important;
212217
-webkit-marquee: auto medium infinite scroll normal !important;
213218
overflow-x: -webkit-marquee !important;
214219
}
@@ -221,13 +226,13 @@ div.menu-action.active::after {
221226
height: 35px;
222227
width: 100px;
223228
border-radius: 2px;
224-
color: black;
229+
color: var(--font-color);
230+
background-color: var(--bg-primary);
225231
font-size: 15px;
226232
pointer-events: all;
227-
border: 1px solid gray;
233+
border: 1px solid var(--border-color);
228234
text-align: left;
229235
vertical-align: bottom;
230-
231236
-webkit-transition: all .5s;
232237
-moz-transition: all .5s;
233238
-o-transition: all .5s;
@@ -242,23 +247,23 @@ button.active::after {
242247
display: inline-block;
243248
margin: auto auto auto 10px;
244249
font-weight: bold;
245-
246250
white-space: nowrap;
247251
overflow: hidden;
248252
text-overflow: ellipsis;
253+
color: var(--font-color);
249254
}
250255

251-
252256
.details-header {
253257
padding-top: 5px;
254258
padding-bottom: 5px;
255259
cursor: move;
256-
background-color: white;
260+
background-color: var(--bg-primary);
257261
margin: auto;
258262
display: flex;
259263
justify-content: space-between;
260264
flex-direction: row;
261-
border-bottom: 1px solid lightgrey;
265+
border-bottom: 1px solid var(--border-color);
266+
color: var(--font-color);
262267
}
263268

264269
.close-button {
@@ -267,27 +272,27 @@ button.active::after {
267272
background: inherit;
268273
border: none;
269274
cursor: pointer !important;
275+
color: var(--font-color);
270276
}
271277

272278
.details-footer {
273-
background-color: white;
279+
background-color: var(--bg-primary);
274280
display: flex;
275281
justify-content: flex-end;
276282
flex-direction: row;
277-
border-top: 1px solid lightgrey;
283+
border-top: 1px solid var(--border-color);
278284
height: 40px;
279285
}
280286

281287
.details-footer-button {
282-
background: #4c6b9e;
283-
color: white;
288+
background: var(--accent-color);
289+
color: var(--accent-text-color);
284290
height: 70%;
285291
float: right;
286292
border-radius: 2px;
287293
border: none;
288294
margin-right: 20px;
289295
margin-top: 10px;
290-
291296
}
292297

293298
.right-actions {

src/graph_notebook/widgets/src/force_widget.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
VisNode,
2424
} from "./types";
2525
import { MODULE_NAME, MODULE_VERSION } from "./version";
26+
import { initThemeDetection } from "./theme_manager";
2627

2728
import feather from "feather-icons";
2829
import $ from "jquery";
@@ -113,6 +114,9 @@ export class ForceView extends DOMWidgetView {
113114
private physicsBtn = document.createElement("button");
114115

115116
render(): void {
117+
// Initialize theme detection for dark mode compatibility
118+
initThemeDetection();
119+
116120
// Add jQuery UI CSS via CDN
117121
const jqueryUICss = document.createElement('link');
118122
jqueryUICss.rel = 'stylesheet';
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
/**
7+
* Theme manager for graph-notebook widgets
8+
*
9+
* Detect and adapt to JupyterLab themes by applying CSS variables from the current JupyterLab
10+
* theme to widget elements.
11+
*/
12+
13+
/**
14+
* Initialize theme detection and apply the custom theme styles to make the widgets compatible
15+
* with JupyterLab's themes.
16+
*/
17+
export function initThemeDetection(): void {
18+
const isJupyterLab = document.body.classList.contains('jp-Notebook') ||
19+
document.body.classList.contains('jp-NotebookPanel');
20+
21+
if (!isJupyterLab) {
22+
console.log('Not running in JupyterLab, skipping theme detection');
23+
24+
return;
25+
}
26+
27+
applyThemeStyles();
28+
29+
const observer = new MutationObserver((mutations) => {
30+
mutations.forEach((mutation) => {
31+
if (mutation.attributeName === 'data-jp-theme-name' ||
32+
mutation.attributeName === 'class') {
33+
applyThemeStyles();
34+
}
35+
});
36+
});
37+
38+
// Observe document body for theme change
39+
observer.observe(document.body, {
40+
attributes: true,
41+
attributeFilter: ['data-jp-theme-name', 'class']
42+
});
43+
}
44+
45+
/**
46+
* Apply theme-specific styles
47+
*/
48+
function applyThemeStyles(): void {
49+
// Update SVG icon stroke
50+
const featherIcons = document.querySelectorAll('.feather');
51+
52+
featherIcons.forEach((icon: Element) => {
53+
(icon as SVGElement).style.stroke = 'var(--icon-stroke)';
54+
});
55+
}

0 commit comments

Comments
 (0)