Compare commits

...

2 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
e1986611c1 Add high contrast theme support for Monaco Editor
- Add GetMonacoTheme() to ThemeManager for detecting high contrast mode
- Update Monaco index.html to support hc-black and hc-light themes
- Update Monaco Preview Handler to use high contrast themes
- Update Peek to use high contrast themes
- Update Registry Preview to detect and use high contrast themes

Co-authored-by: yeelam-gordon <73506701+yeelam-gordon@users.noreply.github.com>
2026-02-05 15:20:31 +00:00
copilot-swe-agent[bot]
71d55ac50f Initial plan 2026-02-05 15:17:01 +00:00
5 changed files with 67 additions and 13 deletions

View File

@@ -6,14 +6,15 @@
// Get URL parameters:
// `code` contains the code of the file in base64 encoded
// `theme` can be "vs" for light theme or "vs-dark" for dark theme
// `theme` can be "vs" for light theme, "vs-dark" for dark theme,
// "hc-black" for dark high contrast, or "hc-light" for light high contrast
// `lang` is the language of the file
// `wrap` if the editor is wrapping or not
// `minimap` if the minimap is shown
// `contextMenu` whether to use the Monaco context menu. The built-in context menu
// doesn't work in Peek, so we set this to false and create a custom one
var theme = ("[[PT_THEME]]" == "dark") ? "vs-dark" : "vs";
var theme = "[[PT_THEME]]";
var wrap = [[PT_WRAP]];
var minimap = [[PT_MINIMAP]];
var stickyScroll = [[PT_STICKY_SCROLL]];
@@ -87,13 +88,20 @@
require(['vs/editor/editor.main'], async function () {
await registerAdditionalLanguages(monaco)
// Creates a theme to handle custom tokens
monaco.editor.defineTheme('theme', {
base: theme, // Sets the base theme to "vs" or "vs-dark" depending on the user's preference
inherit: true,
rules: customTokenThemeRules,
colors: {} // `colors` is a required attribute
});
// For high contrast themes, use Monaco's built-in themes directly
// For normal themes, create a custom theme to handle custom tokens
var editorTheme = theme;
if (theme === 'vs' || theme === 'vs-dark') {
// Creates a theme to handle custom tokens
monaco.editor.defineTheme('custom-theme', {
base: theme, // Sets the base theme to "vs" or "vs-dark" depending on the user's preference
inherit: true,
rules: customTokenThemeRules,
colors: {} // `colors` is a required attribute
});
editorTheme = 'custom-theme';
}
// For hc-black and hc-light, use the built-in Monaco themes which have proper contrast
// Creates the editor
// For all parameters: https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IStandaloneEditorConstructionOptions.html
@@ -101,7 +109,7 @@
value: code, // Sets content of the editor
language: lang, // Sets language of the code
readOnly: true, // Sets to readonly
theme: 'theme', // Sets editor theme
theme: editorTheme, // Sets editor theme
minimap: { enabled: minimap }, // Controls if minimap is shown
lineNumbersMinChars: 3, // Width of the line numbers
contextmenu: contextMenu,

View File

@@ -113,6 +113,26 @@ namespace Common.UI
return ControlzEx.Theming.WindowsThemeHelper.GetWindowsBaseColor();
}
/// <summary>
/// Gets the Monaco theme name based on Windows theme and high contrast mode.
/// </summary>
/// <returns>Monaco theme name: "hc-black", "hc-light", "vs-dark", or "vs".</returns>
public static string GetMonacoTheme()
{
if (ControlzEx.Theming.WindowsThemeHelper.IsHighContrastEnabled())
{
// In high contrast mode, check if it's a dark or light high contrast theme
string baseColor = ControlzEx.Theming.WindowsThemeHelper.GetWindowsBaseColor();
return baseColor.Equals("Dark", StringComparison.OrdinalIgnoreCase) ? "hc-black" : "hc-light";
}
else
{
// Normal mode: use standard themes
string baseColor = ControlzEx.Theming.WindowsThemeHelper.GetWindowsBaseColor();
return baseColor.Equals("Dark", StringComparison.OrdinalIgnoreCase) ? "vs-dark" : "vs";
}
}
public void ChangeTheme(Theme theme, bool fromSettings = false)
{
if (fromSettings)

View File

@@ -75,7 +75,7 @@ namespace Peek.FilePreviewer.Previewers
}
string base64FileCode = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(fileContent));
string theme = ThemeManager.GetWindowsBaseColor().ToLowerInvariant();
string theme = ThemeManager.GetMonacoTheme();
// prepping index html to load in
string html = Microsoft.PowerToys.FilePreviewCommon.MonacoHelper.ReadIndexHtml();

View File

@@ -197,7 +197,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
/// <returns>Theme that should be used.</returns>
public static string GetTheme()
{
return Common.UI.ThemeManager.GetWindowsBaseColor().ToLowerInvariant();
return Common.UI.ThemeManager.GetMonacoTheme();
}
}
}

View File

@@ -16,6 +16,7 @@ using Microsoft.Web.WebView2.Core;
using Windows.ApplicationModel.DataTransfer;
using Windows.System;
using Windows.UI;
using Windows.UI.ViewManagement;
namespace RegistryPreviewUILib
{
@@ -148,10 +149,35 @@ namespace RegistryPreviewUILib
private async Task SetThemeAsync()
{
var theme = Application.Current.RequestedTheme == ApplicationTheme.Light ? "vs" : "vs-dark";
var theme = GetMonacoTheme();
await Browser.CoreWebView2.ExecuteScriptAsync($"monaco.editor.setTheme('{theme}')");
}
private static string GetMonacoTheme()
{
var uiSettings = new UISettings();
var highContrast = uiSettings.HighContrast;
if (highContrast)
{
// In high contrast mode, check if it's a dark or light high contrast theme
var foreground = uiSettings.GetColorValue(UIColorType.Foreground);
var background = uiSettings.GetColorValue(UIColorType.Background);
// Determine if it's a dark theme by comparing luminance
// Dark themes have light foreground and dark background
var foregroundLuminance = (0.299 * foreground.R + 0.587 * foreground.G + 0.114 * foreground.B) / 255;
var backgroundLuminance = (0.299 * background.R + 0.587 * background.G + 0.114 * background.B) / 255;
return backgroundLuminance < foregroundLuminance ? "hc-black" : "hc-light";
}
else
{
// Normal mode: use standard themes based on app theme
return Application.Current.RequestedTheme == ApplicationTheme.Light ? "vs" : "vs-dark";
}
}
private void OnTextChangedThrottleElapsed(object sender, ElapsedEventArgs e)
{
if (_textChangedThrottled)