Conversation
|
Converting to draft, this breaks the change icon menu entry on the file explorer and regular tabs. |
This reverts commit 1d4c935.
|
Couldn't figure out a good way to fix the context menu issue, but the icon compatibility is all right. Reverted the broken context menu fix. Should be ready to squash merge. |
|
Hi @Stonks3141 @gfxholo ! Thanks so much for your work on making Iconic compatible with Vertical Tabs. I’m the developer of Vertical Tabs, and I wanted to let you know that Vertical Tabs now provides an API for modifying menus and setting tab icons. You can find the documentation here. At the moment, the API is available to Beta Program subscribers. If you’d like free access to the beta versions, feel free to reply here or reach out to me directly, and I’ll send you an invitation link. Thanks again for your contribution! |
| @@ -34,6 +41,7 @@ export default class TabIconManager extends IconManager { | |||
| }); | |||
|
|
|||
| this.refreshIcons(); | |||
| this.observeVerticalTabs(); | |||
| } | |||
|
|
|||
| /** | |||
| @@ -142,6 +150,8 @@ export default class TabIconManager extends IconManager { | |||
| } | |||
| } | |||
| } | |||
|
|
|||
| this.refreshVerticalTabsIcons(unloading); | |||
| } | |||
|
|
|||
| /** | |||
| @@ -238,6 +248,87 @@ export default class TabIconManager extends IconManager { | |||
| } | |||
| } | |||
|
|
|||
| /** | |||
| * Get the Vertical Tabs plugin container element, if present. | |||
| */ | |||
| private getVerticalTabsContainer(): HTMLElement | null { | |||
| const leaves = this.app.workspace.getLeavesOfType(VERTICAL_TABS_VIEW_TYPE); | |||
| if (leaves.length === 0) return null; | |||
| return leaves[0].view.containerEl ?? null; | |||
| } | |||
|
|
|||
| /** | |||
| * Set up MutationObserver to catch Vertical Tabs React re-renders. | |||
| */ | |||
| private observeVerticalTabs(): void { | |||
| const vtContainer = this.getVerticalTabsContainer(); | |||
| if (!vtContainer) return; | |||
|
|
|||
| this.setMutationObserver(vtContainer, { childList: true, subtree: true }, () => { | |||
| if (this.vtObserverTimeout) window.cancelAnimationFrame(this.vtObserverTimeout); | |||
| this.vtObserverTimeout = window.requestAnimationFrame(() => { | |||
| this.refreshVerticalTabsIcons(); | |||
| }); | |||
| }); | |||
| } | |||
|
|
|||
| /** | |||
| * Refresh icons in Vertical Tabs plugin view. | |||
| */ | |||
| private refreshVerticalTabsIcons(unloading?: boolean): void { | |||
| const vtContainer = this.getVerticalTabsContainer(); | |||
| if (!vtContainer) return; | |||
|
|
|||
| // Build a map of leaf IDs to leaves | |||
| const leafMap = new Map<string, WorkspaceLeaf>(); | |||
| this.app.workspace.iterateAllLeaves(leaf => { | |||
| // @ts-expect-error (Private API) | |||
| leafMap.set(leaf.id, leaf); | |||
| }); | |||
|
|
|||
| const vtTabs = vtContainer.querySelectorAll('.tree-item.is-tab'); | |||
|
|
|||
| for (const vtTabEl of vtTabs) { | |||
| const leafId = vtTabEl.getAttribute('data-id'); | |||
| if (!leafId) continue; | |||
|
|
|||
| const vtIconEl = vtTabEl.querySelector(':scope > .tree-item-self > .tree-item-icon') as HTMLElement | null; | |||
| if (!vtIconEl) continue; | |||
|
|
|||
| const leaf = leafMap.get(leafId); | |||
| if (!leaf) continue; | |||
|
|
|||
| const viewType = leaf.view.getViewType(); | |||
| if (viewType === 'webviewer') continue; | |||
| const filePath = leaf.view.getState().file; | |||
|
|
|||
| let icon: string | null = null; | |||
| let color: string | null = null; | |||
| let iconDefault: string | null = leaf.view.getIcon(); | |||
| let category: Category = 'tab'; | |||
| let id: string = viewType; | |||
|
|
|||
| if (filePath && !PLUGIN_TAB_TYPES.includes(viewType)) { | |||
| category = 'file'; | |||
| id = typeof filePath === 'string' ? filePath : ''; | |||
| const fileIcon = this.plugin.settings.fileIcons[id] ?? {}; | |||
| icon = unloading ? null : fileIcon.icon ?? null; | |||
| color = unloading ? null : fileIcon.color ?? null; | |||
| } else { | |||
| const tabIcon = this.plugin.settings.tabIcons[viewType] ?? {}; | |||
| icon = unloading ? null : tabIcon.icon ?? null; | |||
| color = unloading ? null : tabIcon.color ?? null; | |||
| } | |||
|
|
|||
| const item = { id, name: leaf.getDisplayText(), icon, color, iconDefault, category }; | |||
| const rule = category === 'file' | |||
| ? this.plugin.ruleManager.checkRuling('file', id, unloading) ?? item | |||
| : item; | |||
|
|
|||
| this.refreshIcon(rule, vtIconEl); | |||
| } | |||
| } | |||
|
|
|||
There was a problem hiding this comment.
It would be faster to use app.workspace.getLeafById(id) than building a map.
Makes icons correctly appear in Vertical Tabs (#204) and fixes the bug where context menus in Vertical Tabs instantly vanish (#110). The Vertical Tabs context menu doesn't have the Change Icon/Remove Icon entries, I couldn't figure out how to make that work.