Skip to content

Commit 6e69f89

Browse files
committed
feat(menu): use material icons for files and folders
1 parent 30c44ff commit 6e69f89

File tree

4 files changed

+66
-18
lines changed

4 files changed

+66
-18
lines changed

package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@
454454
"tmp": "^0.2.3",
455455
"tree-sitter-wasms": "^0.1.11",
456456
"turndown": "^7.2.0",
457+
"vscode-material-icons": "^0.1.1",
457458
"web-tree-sitter": "^0.22.6",
458459
"zod": "^3.23.8"
459460
},

src/core/webview/ClineProvider.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,13 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
621621
"codicon.css",
622622
])
623623

624+
const materialIconsUri = getUri(webview, this.contextProxy.extensionUri, [
625+
"node_modules",
626+
"vscode-material-icons",
627+
"generated",
628+
"icons",
629+
])
630+
624631
const imagesUri = getUri(webview, this.contextProxy.extensionUri, ["assets", "images"])
625632

626633
const file = "src/index.tsx"
@@ -656,6 +663,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
656663
<link href="${codiconsUri}" rel="stylesheet" />
657664
<script nonce="${nonce}">
658665
window.IMAGES_BASE_URI = "${imagesUri}"
666+
window.MATERIAL_ICONS_BASE_URI = "${materialIconsUri}"
659667
</script>
660668
<title>Roo Code</title>
661669
</head>
@@ -705,6 +713,14 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
705713
"codicon.css",
706714
])
707715

716+
// The material icons from the React build output
717+
const materialIconsUri = getUri(webview, this.contextProxy.extensionUri, [
718+
"node_modules",
719+
"vscode-material-icons",
720+
"generated",
721+
"icons",
722+
])
723+
708724
const imagesUri = getUri(webview, this.contextProxy.extensionUri, ["assets", "images"])
709725

710726
// const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, "assets", "main.js"))
@@ -741,6 +757,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
741757
<link href="${codiconsUri}" rel="stylesheet" />
742758
<script nonce="${nonce}">
743759
window.IMAGES_BASE_URI = "${imagesUri}"
760+
window.MATERIAL_ICONS_BASE_URI = "${materialIconsUri}"
744761
</script>
745762
<title>Roo Code</title>
746763
</head>

webview-ui/src/components/chat/ContextMenu.tsx

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import React, { useEffect, useMemo, useRef } from "react"
1+
import React, { useEffect, useMemo, useRef, useState } from "react"
2+
import { getIconForFilePath, getIconUrlByName, getIconForDirectoryPath } from "vscode-material-icons"
23
import {
34
ContextMenuOptionType,
45
ContextMenuQueryItem,
@@ -33,6 +34,7 @@ const ContextMenu: React.FC<ContextMenuProps> = ({
3334
loading = false,
3435
dynamicSearchResults = [],
3536
}) => {
37+
const [materialIconsBaseUri, setMaterialIconsBaseUri] = useState("")
3638
const menuRef = useRef<HTMLDivElement>(null)
3739

3840
const filteredOptions = useMemo(() => {
@@ -55,6 +57,12 @@ const ContextMenu: React.FC<ContextMenuProps> = ({
5557
}
5658
}, [selectedIndex])
5759

60+
// get the icons base uri on mount
61+
useEffect(() => {
62+
const w = window as any
63+
setMaterialIconsBaseUri(w.MATERIAL_ICONS_BASE_URI)
64+
}, [])
65+
5866
const renderOptionContent = (option: ContextMenuQueryItem) => {
5967
switch (option.type) {
6068
case ContextMenuOptionType.Mode:
@@ -173,6 +181,15 @@ const ContextMenu: React.FC<ContextMenuProps> = ({
173181
}
174182
}
175183

184+
const getMaterialIconForOption = (option: ContextMenuQueryItem): string => {
185+
// only take the last part of the path to handle both file and folder icons
186+
// since material-icons have specific folder icons, we use them if available
187+
const name = option.value?.split("/").filter(Boolean).at(-1) ?? ""
188+
const iconName =
189+
option.type === ContextMenuOptionType.Folder ? getIconForDirectoryPath(name) : getIconForFilePath(name)
190+
return getIconUrlByName(iconName, materialIconsBaseUri)
191+
}
192+
176193
const isOptionSelectable = (option: ContextMenuQueryItem): boolean => {
177194
return option.type !== ContextMenuOptionType.NoResults && option.type !== ContextMenuOptionType.URL
178195
}
@@ -229,17 +246,35 @@ const ContextMenu: React.FC<ContextMenuProps> = ({
229246
overflow: "hidden",
230247
paddingTop: 0,
231248
}}>
232-
{option.type !== ContextMenuOptionType.Mode && getIconForOption(option) && (
233-
<i
234-
className={`codicon codicon-${getIconForOption(option)}`}
249+
{(option.type === ContextMenuOptionType.File ||
250+
option.type === ContextMenuOptionType.Folder ||
251+
option.type === ContextMenuOptionType.OpenedFile) && (
252+
<img
253+
src={getMaterialIconForOption(option)}
254+
alt="Mode"
235255
style={{
236256
marginRight: "6px",
237257
flexShrink: 0,
238-
fontSize: "14px",
239-
marginTop: 0,
258+
width: "16px",
259+
height: "16px",
240260
}}
241261
/>
242262
)}
263+
{option.type !== ContextMenuOptionType.Mode &&
264+
option.type !== ContextMenuOptionType.File &&
265+
option.type !== ContextMenuOptionType.Folder &&
266+
option.type !== ContextMenuOptionType.OpenedFile &&
267+
getIconForOption(option) && (
268+
<i
269+
className={`codicon codicon-${getIconForOption(option)}`}
270+
style={{
271+
marginRight: "6px",
272+
flexShrink: 0,
273+
fontSize: "14px",
274+
marginTop: 0,
275+
}}
276+
/>
277+
)}
243278
{renderOptionContent(option)}
244279
</div>
245280
{(option.type === ContextMenuOptionType.File ||
@@ -251,18 +286,6 @@ const ContextMenu: React.FC<ContextMenuProps> = ({
251286
style={{ fontSize: "10px", flexShrink: 0, marginLeft: 8 }}
252287
/>
253288
)}
254-
{(option.type === ContextMenuOptionType.Problems ||
255-
option.type === ContextMenuOptionType.Terminal ||
256-
((option.type === ContextMenuOptionType.File ||
257-
option.type === ContextMenuOptionType.Folder ||
258-
option.type === ContextMenuOptionType.OpenedFile ||
259-
option.type === ContextMenuOptionType.Git) &&
260-
option.value)) && (
261-
<i
262-
className="codicon codicon-add"
263-
style={{ fontSize: "10px", flexShrink: 0, marginLeft: 8 }}
264-
/>
265-
)}
266289
</div>
267290
))
268291
) : (

0 commit comments

Comments
 (0)