Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions source/npm/qsharp/ux/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ export { EstimatesOverview } from "./estimatesOverview.js";
export { EstimatesPanel } from "./estimatesPanel.js";
export { Circuit, CircuitPanel } from "./circuit.js";
export { setRenderer, Markdown } from "./renderers.js";
export { detectThemeChange, updateGitHubTheme } from "./themeObserver.js";
176 changes: 176 additions & 0 deletions source/npm/qsharp/ux/qdk-theme.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/* Copyright (c) Microsoft Corporation.
Licensed under the MIT License. */

/*
CSS is tricky get get right across environments we care about. This file attempts to centralize some of the nuances.

It is structured into two parts:

1. Set the variables for the color palette based on the current theme (light/dark).
2. Set variables for the specific ux elements based on the color palette variables.

Specifying ANY color values (e.g. `red`, `#ff0000`, etc) should only be done via the variables in part 1.
Other styles that need colors should ONLY reference those variables, or via variables derived from them.

This ensures that when the theme changes, all widgets automatically update to the correct colors, and
our `palette` of colors is consistent across all widgets.

=== HOW THIS SETS THEME COLORS ===

We want to set colors based on the current theme. This could be:

1. The theme set in VS Code.
2. The theme in Jupyter running in the browser.
3. A theme set on the host page (e.g. the katas viewer on the playground).
4. If none of the above, use the user system preference for light/dark mode.

The goal is to use CSS selectors and variables to ensure the right colors are applied in each case,
with the 'cascade' ensuring the correct precedence.

Note that the 'default' light mode values (no attribute set and no browser preference) are always
on the :root selector (typically the html element), and then overridden via the media query is the
browser preference is dark mode. This ensures that if nothing is set anywhere, the system preference is used.

The theme attributes on the body element (set by VS Code or Jupter) will be closer to the element being
styled than the :root selector, so will take precedence in the cascade if set.

=== ENVIRONMENT SPECIFIC SELECTORS ===

There are a number of selectors we can use for various environments:

- VS Code will use one of the below attributes on the body element (including the body in the iframe
for the notebook cells when running Jupyter in VS Code). The first 2 are light, the second 2 are dark:

- [data-vscode-theme-kind="vscode-light"]
- [data-vscode-theme-kind="vscode-high-contrast-light"]
- [data-vscode-theme-kind="vscode-dark"]
- [data-vscode-theme-kind="vscode-high-contrast"]

- Jupyter in the browser will use one of the below attributes on the body element for light/dark themes:

- [data-jp-theme-light="true"]
- [data-jp-theme-light="false"]

- It is also common to use a [data-theme="light"] or [data-theme="dark"] attribute on the body element
to indicate light/dark themes, so look for that also (e.g. in the kata viewer in the playground).

- If none of the above are present, then none of the theme specific values will have been set on the body
element, and we fall back to using the :root selector combined with a media query for the values.

Note that colors that are not theme dependent should just be set on :root, with no need to add overrides
*/

/* Default to light values set on :root if all else fails */
:root,
/* Set these variables on the body element if attributes indicate a light theme choice */
body[data-theme="light"],
body[data-jp-theme-light="true"],
body[data-vscode-theme-kind="vscode-light"],
body[data-vscode-theme-kind="vscode-high-contrast-light"] {
/* First set the non-theme specific values here only */
--qdk-font-family-monospace: var(
--vscode-editor-font-family,
"Consolas",
"Menlo",
"Liberation Mono",
monospace
);
--qdk-mid-gray: #888;

/* Use the host foreground/background if available */
--qdk-host-background: var(
--vscode-editor-background,
var(--jp-layout-color0, #eee)
);
--qdk-host-foreground: var(
--vscode-editor-foreground,
var(--jp-widgets-color, #222)
);

/* Used for text that must stand out on various backgrounds */
--qdk-text-high-contrast: #000;

/* Outline for widget borders, etc. */
--qdk-widget-outline: #ccc;

/* Use for menus */
--qdk-menu-fill: #ccc;
--qdk-menu-fill-hover: #9cf;
--qdk-menu-fill-selected: #7af;

/* Used for shapes in charts, etc. that may have overlapping text (which should contrast) */
--qdk-shape-fill: #8ab8ff;
--qdk-shape-fill-selected: #b5c5f2;
--qdk-shape-stroke-selected: #587ddd;
--qdk-shape-stroke-hover: #6b6b6b;
}

/* Dark theme styles to use on :root if no attributes are set, but the OS/browser preferences is dark mode

This has exactly the same specificity and location in the CSS cascade as the defaults set on :root above,
but will override those :root defaults if the media query matches, as these styles come later in the file.
*/
@media (prefers-color-scheme: dark) {
:root {
/* Use the host foreground/background if available */
--qdk-host-background: var(
--vscode-editor-background,
var(--jp-layout-color0, #222)
);
--qdk-host-foreground: var(
--vscode-editor-foreground,
var(--jp-widgets-color, #eee)
);

/* Used for text that must stand out on various backgrounds */
--qdk-text-high-contrast: #fff;

/* Outline for widget borders, etc. */
--qdk-widget-outline: #444;

/* Use for menus */
--qdk-menu-fill: #444;
--qdk-menu-fill-hover: #468;
--qdk-menu-fill-selected: #47a;

/* Used for shapes in charts, etc. that may have overlapping text (which should contrast) */
--qdk-shape-fill: #4aa3ff;
--qdk-shape-fill-selected: #ffd54f;
--qdk-shape-stroke-selected: #ffecb3;
--qdk-shape-stroke-hover: #c5c5c5;
}
}

/* Set these variables on the body element if attributes indicate a dark theme choice */
/* Note these should repeat the above entries in the media query for dark theme. Sadly, no way to avoid this */
body[data-theme="dark"],
body[data-jp-theme-light="false"],
body[data-vscode-theme-kind="vscode-dark"],
body[data-vscode-theme-kind="vscode-high-contrast"] {
/* Use the host foreground/background if available */
--qdk-host-background: var(
--vscode-editor-background,
var(--jp-layout-color0, #222)
);
--qdk-host-foreground: var(
--vscode-editor-foreground,
var(--jp-widgets-color, #eee)
);

/* Used for text that must stand out on various backgrounds */
--qdk-text-high-contrast: #fff;

/* Outline for widget borders, etc. */
--qdk-widget-outline: #444;

/* Use for menus */
--qdk-menu-fill: #444;
--qdk-menu-fill-hover: #468;
--qdk-menu-fill-selected: #47a;

/* Used for shapes in charts, etc. that may have overlapping text (which should contrast) */
--qdk-shape-fill: #4aa3ff;
--qdk-shape-fill-selected: #ffd54f;
--qdk-shape-stroke-selected: #ffecb3;
--qdk-shape-stroke-hover: #c5c5c5;
}
110 changes: 25 additions & 85 deletions source/npm/qsharp/ux/qsharp-ux.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* Copyright (c) Microsoft Corporation.
Licensed under the MIT License. */

@import "./qdk-theme.css";

/* Styles for Q# UX components.

Notes:
Expand Down Expand Up @@ -48,57 +50,6 @@ modern-normalize (see https://mattbrictson.com/blog/css-normalize-and-reset for
--error-background-color: #ffe3e3;
--warning-background-color: #fff6d7;
--bar-selected-outline: #587ddd;

/* Histogram palette (light scheme by default; used when no VS Code theme is detected) */
--qs-histogram-bg: #ffffff;
--qs-histogram-border: #768f9c;
--qs-histogram-bar-fill: #8ab8ff;
--qs-histogram-bar-hover-stroke: #6b6b6b;
--qs-histogram-bar-selected-fill: #b5c5f2;
--qs-histogram-bar-selected-stroke: #587ddd;
--qs-histogram-bar-label-fill: #202020;
--qs-histogram-label-fill: #3b3b3b;
--qs-histogram-hover-text-fill: #6b6b6b;
--qs-histogram-menu-icon-stroke: #3b3b3b;
--qs-histogram-menu-icon-fill: #ffffff;
--qs-histogram-menu-box-fill: #ffffff;
--qs-histogram-menu-box-stroke: #3b3b3b;
--qs-histogram-menu-item-fill: #b7d5ff;
--qs-histogram-menu-item-hover-fill: #9fc7ff;
--qs-histogram-menu-item-stroke: #6b6b6b;
--qs-histogram-menu-item-selected-fill: #6aa9ff;
--qs-histogram-menu-text-fill: #202020;
--qs-histogram-menu-separator-stroke: #6b6b6b;
--qs-histogram-help-fill: #ffffff;
--qs-histogram-help-stroke: #6b6b6b;
--qs-histogram-help-text-fill: #202020;
}

/* Histogram palette overrides for dark themes. */
body[data-vscode-theme-kind="vscode-dark"],
body[data-vscode-theme-kind="vscode-high-contrast"] {
--qs-histogram-bg: #1e1e1e;
--qs-histogram-border: #3c3c3c;
--qs-histogram-bar-fill: #4aa3ff;
--qs-histogram-bar-hover-stroke: #c5c5c5;
--qs-histogram-bar-selected-fill: #ffd54f;
--qs-histogram-bar-selected-stroke: #ffecb3;
--qs-histogram-bar-label-fill: #ffffff;
--qs-histogram-label-fill: #ffffff;
--qs-histogram-hover-text-fill: #ffffff;
--qs-histogram-menu-icon-stroke: #d4d4d4;
--qs-histogram-menu-icon-fill: #1e1e1e;
--qs-histogram-menu-box-fill: #252526;
--qs-histogram-menu-box-stroke: #d4d4d4;
--qs-histogram-menu-item-fill: #2d2d30;
--qs-histogram-menu-item-hover-fill: #3e3e42;
--qs-histogram-menu-item-stroke: #6b6b6b;
--qs-histogram-menu-item-selected-fill: #094771;
--qs-histogram-menu-text-fill: #ffffff;
--qs-histogram-menu-separator-stroke: #6b6b6b;
--qs-histogram-help-fill: #252526;
--qs-histogram-help-stroke: #6b6b6b;
--qs-histogram-help-text-fill: #ffffff;
}

/* TODO: Make the below playground specific classes */
Expand Down Expand Up @@ -396,108 +347,97 @@ body[data-vscode-theme-kind="vscode-high-contrast"] {
.histogram {
max-height: calc(100vh - 40px);
max-width: 600px;
border: 1px solid var(--qs-histogram-border);
background-color: var(--qs-histogram-bg);
border: 1px solid var(--qdk-widget-outline);
background-color: var(--qdk-host-background);
}

.bar {
fill: var(--qs-histogram-bar-fill);
fill: var(--qdk-shape-fill);
}

.bar:hover {
stroke: var(--qs-histogram-bar-hover-stroke);
stroke: var(--qdk-shape-stroke-hover);
stroke-width: 0.5;
}

.bar-selected {
stroke: var(--qs-histogram-bar-selected-stroke);
fill: var(--qs-histogram-bar-selected-fill);
stroke: var(--qdk-shape-stroke-selected);
fill: var(--qdk-shape-fill-selected);
}

.bar-label {
font-size: 3pt;
fill: var(--qs-histogram-bar-label-fill);
fill: var(--qdk-text-high-contrast);
text-anchor: end;
pointer-events: none;
}

.bar-label-ket {
font-family: var(
--vscode-editor-font-family,
"Consolas",
"Menlo",
"Monaco",
"Liberation Mono",
"Courier New",
monospace
);
font-family: var(--qdk-font-family-monospace);
font-variant-ligatures: none;
font-size: 3.3pt;
}

.histo-label {
font-size: 3.5pt;
fill: var(--qs-histogram-label-fill);
fill: var(--qdk-host-foreground);
}

.hover-text {
font-size: 3.5pt;
fill: var(--qs-histogram-hover-text-fill);
fill: var(--qdk-host-foreground);
text-anchor: middle;
}

.menu-icon * {
fill: var(--qs-histogram-menu-icon-fill);
stroke: var(--qs-histogram-menu-icon-stroke);
fill: var(--qdk-host-background);
stroke: var(--qdk-host-foreground);
}

.menu-box {
fill: var(--qs-histogram-menu-box-fill);
stroke: var(--qs-histogram-menu-box-stroke);
fill: var(--qdk-host-background);
stroke: var(--qdk-host-foreground);
stroke-width: 0.1;
}

.menu-item {
width: 32px;
height: 10px;
fill: var(--qs-histogram-menu-item-fill);
stroke: var(--qs-histogram-menu-item-stroke);
fill: var(--qdk-menu-fill);
stroke: var(--qdk-mid-gray);
stroke-width: 0.2;
}

/* --vscode-list-inactiveSelectionBackground */

.menu-item:hover {
stroke-width: 0.6;
fill: var(--qs-histogram-menu-item-hover-fill);
fill: var(--qdk-menu-fill-hover);
}

.menu-selected {
/* stroke: #0800ff; */
fill: var(--qs-histogram-menu-item-selected-fill);
fill: var(--qdk-menu-fill-selected);
}

.menu-text {
font-size: 4.5px;
pointer-events: none;
fill: var(--qs-histogram-menu-text-fill);
fill: var(--qdk-host-foreground);
}

.menu-separator {
stroke: var(--qs-histogram-menu-separator-stroke);
stroke: var(--qdk-mid-gray);
stroke-width: 0.25;
}

.help-info {
fill: var(--qs-histogram-help-fill);
stroke: var(--qs-histogram-help-stroke);
fill: var(--qdk-host-background);
stroke: var(--qdk-mid-gray);
stroke-width: 0.5;
}

.help-info-text {
font-size: 4.5px;
pointer-events: none;
fill: var(--qs-histogram-help-text-fill);
fill: var(--qdk-host-foreground);
}

/* RE details */
Expand Down
Loading
Loading