import { getIcon, normalizePath } from 'obsidian' import type OmnisearchPlugin from '../main' import { isFileImage, isFilePDF, isFileCanvas, isFileExcalidraw, warnVerbose, } from './utils' import { escapeHTML } from './text-processing' export interface IconPacks { prefixToIconPack: { [prefix: string]: string } iconsPath: string } export async function loadIconData(plugin: OmnisearchPlugin): Promise { const app = plugin.app // Check if the 'obsidian-icon-folder' plugin is installed and enabled // Casting 'app' to 'any' here to avoid TypeScript errors since 'plugins' might not be defined on 'App' const iconFolderPlugin = (app as any).plugins.getPlugin( 'obsidian-icon-folder' ) if (!iconFolderPlugin) { return {} } const dataJsonPath = `${app.vault.configDir}/plugins/obsidian-icon-folder/data.json` try { const dataJsonContent = await app.vault.adapter.read(dataJsonPath) const rawIconData = JSON.parse(dataJsonContent) // Normalize keys const iconData: any = {} for (const key in rawIconData) { const normalizedKey = normalizePath(key) iconData[normalizedKey] = rawIconData[key] } return iconData } catch (e) { warnVerbose('Failed to read data.json:', e) return {} } } export async function initializeIconPacks( plugin: OmnisearchPlugin ): Promise { // Add 'Li' prefix for Lucide icons const prefixToIconPack: { [prefix: string]: string } = { Li: 'lucide-icons' } let iconsPath = 'icons' const app = plugin.app // Access the obsidian-icon-folder plugin const iconFolderPlugin = (app as any).plugins.getPlugin( 'obsidian-icon-folder' ) if (iconFolderPlugin) { // Get the icons path from the plugin's settings const iconFolderSettings = iconFolderPlugin.settings iconsPath = iconFolderSettings?.iconPacksPath || 'icons' const iconsDir = `${app.vault.configDir}/${iconsPath}` try { const iconPackDirs = await app.vault.adapter.list(iconsDir) if (iconPackDirs.folders && iconPackDirs.folders.length > 0) { for (const folderPath of iconPackDirs.folders) { const pathParts = folderPath.split('/') const iconPackName = pathParts[pathParts.length - 1] const prefix = createIconPackPrefix(iconPackName) prefixToIconPack[prefix] = iconPackName } } } catch (e) { warnVerbose('Failed to list icon packs:', e) } } return { prefixToIconPack, iconsPath } } function createIconPackPrefix(iconPackName: string): string { if (iconPackName.includes('-')) { const splitted = iconPackName.split('-') let result = splitted[0].charAt(0).toUpperCase() for (let i = 1; i < splitted.length; i++) { result += splitted[i].charAt(0).toLowerCase() } return result } return ( iconPackName.charAt(0).toUpperCase() + iconPackName.charAt(1).toLowerCase() ) } export function getIconNameForPath(path: string, iconData: any): string | null { const normalizedPath = normalizePath(path) const iconEntry = iconData[normalizedPath] if (iconEntry) { if (typeof iconEntry === 'string') { return iconEntry } else if (typeof iconEntry === 'object' && iconEntry.iconName) { return iconEntry.iconName } } return null } export function parseIconName(iconName: string): { prefix: string name: string } { const prefixMatch = iconName.match(/^[A-Z][a-z]*/) if (prefixMatch) { const prefix = prefixMatch[0] const name = iconName.substring(prefix.length) return { prefix, name } } else { // No prefix, treat the entire iconName as the name return { prefix: '', name: iconName } } } export async function loadIconSVG( iconName: string, plugin: OmnisearchPlugin, iconsPath: string, prefixToIconPack: { [prefix: string]: string } ): Promise { const parsed = parseIconName(iconName) const { prefix, name } = parsed if (!prefix) { // No prefix, assume it's an emoji or text return `${escapeHTML( name )}` } const iconPackName = prefixToIconPack[prefix] if (!iconPackName) { warnVerbose(`No icon pack found for prefix: ${prefix}`) return null } if (iconPackName === 'lucide-icons') { // Convert CamelCase to dash-case for Lucide icons const dashedName = name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase() const iconEl = getIcon(dashedName) if (iconEl) { return iconEl.outerHTML } else { warnVerbose(`Lucide icon not found: ${dashedName}`) return null } } else { if (!iconsPath) { warnVerbose('Icons path is not set. Cannot load icon SVG.') return null } const iconPath = `${plugin.app.vault.configDir}/${iconsPath}/${iconPackName}/${name}.svg` try { const svgContent = await plugin.app.vault.adapter.read(iconPath) return svgContent } catch (e) { warnVerbose(`Failed to load icon SVG for ${iconName} at ${iconPath}:`, e) return null } } } export function getDefaultIconSVG(notePath: string): string { // Return SVG content for default icons based on file type let iconName = 'file' if (notePath === 'folder') { iconName = 'folder' } else { if (isFileImage(notePath)) { iconName = 'image' } else if (isFilePDF(notePath)) { iconName = 'file-text' } else if (isFileCanvas(notePath) || isFileExcalidraw(notePath)) { iconName = 'layout-dashboard' } } const iconEl = getIcon(iconName) return iconEl ? iconEl.outerHTML : '' }