From 9f69c031ce6d0b55e1c361bcf9e98f9f6fa57e1b Mon Sep 17 00:00:00 2001 From: abose Date: Fri, 10 Apr 2026 23:56:37 +0530 Subject: [PATCH 1/5] refactor(panel): use SVG icons instead of FontAwesome classes for bottom panel tabs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace iconClass (FontAwesome class strings) with iconSvg (SVG file paths) for all createBottomPanel callers. FA class approach caused inconsistent sizing between fa-solid and fa-brands due to font-weight/font-size quirks that required CSS overrides. SVG icons are rendered via mask-image with background-color: currentColor so they inherit the theme text color automatically — works correctly in both light and dark themes, and for active/inactive tab states. - New SVG files in src/styles/images/: panel-icon-{terminal,problems, search,git,snippets,shortcuts,default}.svg - Updated callers: Terminal, CodeInspection, SearchResultsView, Git, CustomSnippets, DisplayShortcuts, DefaultPanelView - PanelView.js and DefaultPanelView.js set mask-image inline via JS - Removed iconClass support and related CSS overrides --- src/extensions/default/Git/src/Panel.js | 2 +- .../CustomSnippets/main.js | 2 +- .../DisplayShortcuts/main.js | 2 +- src/extensionsIntegrated/Terminal/main.js | 2 +- src/language/CodeInspection.js | 2 +- src/search/SearchResultsView.js | 2 +- src/styles/Extn-BottomPanelTabs.less | 34 +++++++++---------- src/styles/images/panel-icon-default.svg | 1 + src/styles/images/panel-icon-git.svg | 1 + src/styles/images/panel-icon-problems.svg | 1 + src/styles/images/panel-icon-search.svg | 1 + src/styles/images/panel-icon-shortcuts.svg | 1 + src/styles/images/panel-icon-snippets.svg | 1 + src/styles/images/panel-icon-terminal.svg | 1 + src/view/DefaultPanelView.js | 15 ++++---- src/view/PanelView.js | 33 ++++++------------ src/view/WorkspaceManager.js | 4 +-- 17 files changed, 51 insertions(+), 54 deletions(-) create mode 100644 src/styles/images/panel-icon-default.svg create mode 100644 src/styles/images/panel-icon-git.svg create mode 100644 src/styles/images/panel-icon-problems.svg create mode 100644 src/styles/images/panel-icon-search.svg create mode 100644 src/styles/images/panel-icon-shortcuts.svg create mode 100644 src/styles/images/panel-icon-snippets.svg create mode 100644 src/styles/images/panel-icon-terminal.svg diff --git a/src/extensions/default/Git/src/Panel.js b/src/extensions/default/Git/src/Panel.js index a8c4d7c9bb..41a509cbb5 100644 --- a/src/extensions/default/Git/src/Panel.js +++ b/src/extensions/default/Git/src/Panel.js @@ -1240,7 +1240,7 @@ define(function (require, exports) { var $panelHtml = $(panelHtml); $panelHtml.find(".git-available, .git-not-available").hide(); - gitPanel = WorkspaceManager.createBottomPanel("main-git.panel", $panelHtml, 100, Strings.GIT_PANEL_TITLE, {iconClass: "fa-brands fa-git-alt"}); + gitPanel = WorkspaceManager.createBottomPanel("main-git.panel", $panelHtml, 100, Strings.GIT_PANEL_TITLE, {iconSvg: "styles/images/panel-icon-git.svg"}); $gitPanel = gitPanel.$panel; const resizeObserver = new ResizeObserver(_panelResized); resizeObserver.observe($gitPanel[0]); diff --git a/src/extensionsIntegrated/CustomSnippets/main.js b/src/extensionsIntegrated/CustomSnippets/main.js index d533e37701..3235942cba 100644 --- a/src/extensionsIntegrated/CustomSnippets/main.js +++ b/src/extensionsIntegrated/CustomSnippets/main.js @@ -59,7 +59,7 @@ define(function (require, exports, module) { */ function _createPanel() { customSnippetsPanel = WorkspaceManager.createBottomPanel(PANEL_ID, $snippetsPanel, PANEL_MIN_SIZE, - Strings.CUSTOM_SNIPPETS_PANEL_TITLE, {iconClass: "fa-solid fa-code"}); + Strings.CUSTOM_SNIPPETS_PANEL_TITLE, {iconSvg: "styles/images/panel-icon-snippets.svg"}); UIHelper.init(customSnippetsPanel); customSnippetsPanel.show(); diff --git a/src/extensionsIntegrated/DisplayShortcuts/main.js b/src/extensionsIntegrated/DisplayShortcuts/main.js index ceb6e1ca50..3c71d6b0c2 100644 --- a/src/extensionsIntegrated/DisplayShortcuts/main.js +++ b/src/extensionsIntegrated/DisplayShortcuts/main.js @@ -479,7 +479,7 @@ define(function (require, exports, module) { // AppInit.htmlReady() has already executed before extensions are loaded // so, for now, we need to call this ourself panel = WorkspaceManager.createBottomPanel(TOGGLE_SHORTCUTS_ID, $(s), 300, - Strings.KEYBOARD_SHORTCUT_PANEL_TITLE, {iconClass: "fa-solid fa-keyboard"}); + Strings.KEYBOARD_SHORTCUT_PANEL_TITLE, {iconSvg: "styles/images/panel-icon-shortcuts.svg"}); panel.hide(); $shortcutsPanel = $("#shortcuts-panel"); diff --git a/src/extensionsIntegrated/Terminal/main.js b/src/extensionsIntegrated/Terminal/main.js index b55323403c..4647304a6c 100644 --- a/src/extensionsIntegrated/Terminal/main.js +++ b/src/extensionsIntegrated/Terminal/main.js @@ -115,7 +115,7 @@ define(function (require, exports, module) { }; $panel = $(Mustache.render(panelHTML, templateVars)); - panel = WorkspaceManager.createBottomPanel(PANEL_ID, $panel, PANEL_MIN_SIZE, undefined, {iconClass: "fa-solid fa-terminal"}); + panel = WorkspaceManager.createBottomPanel(PANEL_ID, $panel, PANEL_MIN_SIZE, undefined, {iconSvg: "styles/images/panel-icon-terminal.svg"}); // Override focus() so Shift+Escape can transfer focus to the terminal panel.focus = function () { diff --git a/src/language/CodeInspection.js b/src/language/CodeInspection.js index afad847b08..151440ece9 100644 --- a/src/language/CodeInspection.js +++ b/src/language/CodeInspection.js @@ -1240,7 +1240,7 @@ define(function (require, exports, module) { Editor.registerGutter(CODE_INSPECTION_GUTTER, CODE_INSPECTION_GUTTER_PRIORITY); // Create bottom panel to list error details var panelHtml = Mustache.render(PanelTemplate, Strings); - problemsPanel = WorkspaceManager.createBottomPanel("errors", $(panelHtml), 100, Strings.CMD_VIEW_TOGGLE_PROBLEMS, {iconClass: "fa-solid fa-triangle-exclamation"}); + problemsPanel = WorkspaceManager.createBottomPanel("errors", $(panelHtml), 100, Strings.CMD_VIEW_TOGGLE_PROBLEMS, {iconSvg: "styles/images/panel-icon-problems.svg"}); $problemsPanel = $("#problems-panel"); $fixAllBtn = $problemsPanel.find(".problems-fix-all-btn"); $fixAllBtn.click(()=>{ diff --git a/src/search/SearchResultsView.js b/src/search/SearchResultsView.js index 0c8a8c0d16..a90cc63e2e 100644 --- a/src/search/SearchResultsView.js +++ b/src/search/SearchResultsView.js @@ -82,7 +82,7 @@ define(function (require, exports, module) { const self = this; let panelHtml = Mustache.render(searchPanelTemplate, {panelID: panelID}); - this._panel = WorkspaceManager.createBottomPanel(panelName, $(panelHtml), 100, title, {iconClass: "fa-solid fa-magnifying-glass"}); + this._panel = WorkspaceManager.createBottomPanel(panelName, $(panelHtml), 100, title, {iconSvg: "styles/images/panel-icon-search.svg"}); this._$summary = this._panel.$panel.find(".title"); this._$table = this._panel.$panel.find(".table-container"); this._$previewEditor = this._panel.$panel.find(".search-editor-preview"); diff --git a/src/styles/Extn-BottomPanelTabs.less b/src/styles/Extn-BottomPanelTabs.less index c9dc051604..c2cf5bebea 100644 --- a/src/styles/Extn-BottomPanelTabs.less +++ b/src/styles/Extn-BottomPanelTabs.less @@ -144,31 +144,29 @@ } } -/* Tab icon: hidden by default, shown when tabs are collapsed */ -.bottom-panel-tab-icon { - display: none; - font-size: 1rem; - width: 1rem; - text-align: center; - pointer-events: none; -} - -/* Override any FA class specificity (e.g. fa-brands sets font-size: 1.2em) */ -i.panel-titlebar-icon.panel-titlebar-icon { - font-size: 1rem; -} - -img.panel-titlebar-icon { +/* SVG icons rendered as masks so they inherit currentColor (works with light/dark themes). + The mask-image URL is set inline via JS (PanelView.js, DefaultPanelView.js). */ +.panel-titlebar-icon { + display: inline-block; width: 1rem; height: 1rem; vertical-align: middle; + background-color: currentColor; + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-position: center; + mask-position: center; + -webkit-mask-size: contain; + mask-size: contain; + pointer-events: none; } -.default-panel-btn i.panel-titlebar-icon { - font-size: 20px; +/* Tab icon: hidden by default, shown when tabs are collapsed */ +.bottom-panel-tab-icon { + display: none; } -.default-panel-btn img.panel-titlebar-icon { +.default-panel-btn .panel-titlebar-icon { width: 20px; height: 20px; } diff --git a/src/styles/images/panel-icon-default.svg b/src/styles/images/panel-icon-default.svg new file mode 100644 index 0000000000..d1771f5f35 --- /dev/null +++ b/src/styles/images/panel-icon-default.svg @@ -0,0 +1 @@ + diff --git a/src/styles/images/panel-icon-git.svg b/src/styles/images/panel-icon-git.svg new file mode 100644 index 0000000000..999a7a8f68 --- /dev/null +++ b/src/styles/images/panel-icon-git.svg @@ -0,0 +1 @@ + diff --git a/src/styles/images/panel-icon-problems.svg b/src/styles/images/panel-icon-problems.svg new file mode 100644 index 0000000000..a493590a09 --- /dev/null +++ b/src/styles/images/panel-icon-problems.svg @@ -0,0 +1 @@ + diff --git a/src/styles/images/panel-icon-search.svg b/src/styles/images/panel-icon-search.svg new file mode 100644 index 0000000000..9aef29292d --- /dev/null +++ b/src/styles/images/panel-icon-search.svg @@ -0,0 +1 @@ + diff --git a/src/styles/images/panel-icon-shortcuts.svg b/src/styles/images/panel-icon-shortcuts.svg new file mode 100644 index 0000000000..3ce2af0ccd --- /dev/null +++ b/src/styles/images/panel-icon-shortcuts.svg @@ -0,0 +1 @@ + diff --git a/src/styles/images/panel-icon-snippets.svg b/src/styles/images/panel-icon-snippets.svg new file mode 100644 index 0000000000..09e7fd87ca --- /dev/null +++ b/src/styles/images/panel-icon-snippets.svg @@ -0,0 +1 @@ + diff --git a/src/styles/images/panel-icon-terminal.svg b/src/styles/images/panel-icon-terminal.svg new file mode 100644 index 0000000000..06ed2625ba --- /dev/null +++ b/src/styles/images/panel-icon-terminal.svg @@ -0,0 +1 @@ + diff --git a/src/view/DefaultPanelView.js b/src/view/DefaultPanelView.js index 8bbdfd52ba..03e3f9d3ed 100644 --- a/src/view/DefaultPanelView.js +++ b/src/view/DefaultPanelView.js @@ -39,32 +39,32 @@ define(function (require, exports, module) { const _panelButtons = [ { id: "problems", - icon: "fa-solid fa-triangle-exclamation", + iconSvg: "styles/images/panel-icon-problems.svg", label: Strings.CMD_VIEW_TOGGLE_PROBLEMS || "Problems", commandID: Commands.VIEW_TOGGLE_PROBLEMS }, { id: "git", - icon: "fa-brands fa-git-alt", + iconSvg: "styles/images/panel-icon-git.svg", label: Strings.GIT_PANEL_TITLE || "Git", commandID: Commands.CMD_GIT_TOGGLE_PANEL, nativeOnly: true }, { id: "snippets", - icon: "fa-solid fa-code", + iconSvg: "styles/images/panel-icon-snippets.svg", label: Strings.CUSTOM_SNIPPETS_PANEL_TITLE || "Custom Snippets", commandID: Commands.CMD_CUSTOM_SNIPPETS_PANEL }, { id: "shortcuts", - icon: "fa-solid fa-keyboard", + iconSvg: "styles/images/panel-icon-shortcuts.svg", label: Strings.KEYBOARD_SHORTCUT_PANEL_TITLE || "Keyboard Shortcuts", commandID: Commands.HELP_TOGGLE_SHORTCUTS_PANEL }, { id: "terminal", - icon: "fa-solid fa-terminal", + iconSvg: "styles/images/panel-icon-terminal.svg", label: "Terminal", commandID: Commands.VIEW_TERMINAL, nativeOnly: true @@ -99,7 +99,10 @@ define(function (require, exports, module) { .attr("data-command", btn.commandID) .attr("data-btn-id", btn.id) .attr("title", btn.label); - let $icon = $('').addClass(btn.icon); + let $icon = $(''); + const maskUrl = "url('" + btn.iconSvg + "')"; + $icon[0].style.maskImage = maskUrl; + $icon[0].style.webkitMaskImage = maskUrl; let $label = $('').text(btn.label); $button.append($icon).append($label); $buttonsRow.append($button); diff --git a/src/view/PanelView.js b/src/view/PanelView.js index f862e1a57e..bb5ff47446 100644 --- a/src/view/PanelView.js +++ b/src/view/PanelView.js @@ -152,17 +152,12 @@ define(function (require, exports, module) { let $tab = $('
') .toggleClass('active', isActive) .attr('data-panel-id', panel.panelID); - const opts = panel._options; - if (opts.iconClass) { - $tab.append($('') - .addClass(opts.iconClass)); - } else if (opts.iconSvg) { - $tab.append($('') - .attr("src", opts.iconSvg)); - } else { - // Fallback generic icon for panels without a custom icon - $tab.append($('')); - } + const iconSrc = panel._options.iconSvg || "styles/images/panel-icon-default.svg"; + const $icon = $(''); + const maskUrl = "url('" + iconSrc + "')"; + $icon[0].style.maskImage = maskUrl; + $icon[0].style.webkitMaskImage = maskUrl; + $tab.append($icon); $tab.append($('').text(title)); $tab.append($('×').attr('title', Strings.CLOSE)); return $tab; @@ -432,16 +427,11 @@ define(function (require, exports, module) { _overflowDropdown = new DropdownButton.DropdownButton("", hidden, function (item) { const panel = _panelMap[item.panelId]; - let iconHtml = ""; - if (panel && panel._options) { - if (panel._options.iconClass) { - iconHtml = ''; - } else if (panel._options.iconSvg) { - iconHtml = ''; - } - } + const iconSrc = (panel && panel._options && panel._options.iconSvg) + || "styles/images/panel-icon-default.svg"; + const iconStyle = "width:14px;height:14px;margin-right:6px;vertical-align:middle;" + + "mask-image:url('" + iconSrc + "');-webkit-mask-image:url('" + iconSrc + "')"; + const iconHtml = ''; const activeClass = item.panelId === _activeId ? ' style="font-weight:600"' : ''; return { html: '