import twemoji from 'twemoji' ; import * as remixicons from '../remixicons' ; import * as faLine from '../fontawesome/index-line' ; import * as faFill from '../fontawesome/index-fill' ; import * as faBrands from '../fontawesome/index-brands' ; import IconFolderPlugin , { FolderIconObject } from './main' ; import { ExplorerLeaf } from './@types/obsidian' ; import { IconFolderSettings } from './settings' ; /**
 * `transformedIcons` includes all the icon packs with their corresponding prefix.
 */ const transformedIcons = { faFill : Object . keys ( faFill ) . map ( ( iconName ) => 'Fa' + iconName ) , faLine : Object . keys ( faLine ) . map ( ( iconName ) => 'Fa' + iconName ) , faBrands : Object . keys ( faBrands ) . map ( ( iconName ) => 'Fa' + iconName ) , remixIcons : Object . keys ( remixicons ) . map ( ( iconName ) => 'Ri' + iconName ) , } ; private param { string } iconName param { IconFolderSettings } settings returns { boolean } const mapRemixicons = ( iconName , settings ) : boolean => { if ( iconName . toLowerCase ( ) . includes ( 'fill' ) ) { return settings . enableRemixiconsFill ; } else if ( iconName . toLowerCase ( ) . includes ( 'line' ) ) { return settings . enableRemixiconsLine ; } return true ; } ; public param { IconFolderPlugin } plugin returns { string [ ] } export const getEnabledIcons = ( plugin ) : string [ ] => { const settings = plugin . getSettings ( ) ; const icons = transformedIcons . remixIcons . filter ( ( key ) => { return mapRemixicons ( key , settings ) ; } ) ; if ( settings . enableFontawesomeFill ) { icons . push ( ... transformedIcons . faFill ) ; } if ( settings . enableFontawesomeLine ) { icons . push ( ... transformedIcons . faLine ) ; } if ( settings . enableFontawesomeBrands ) { icons . push ( ... transformedIcons . faBrands ) ; } return icons ; } ; public param { string } name returns { string | null } export const getIcon = ( name ) : string | null => { const prefix = name . substr ( 0 , 2 ) ; let iconSvg = null ; if ( prefix === 'Fa' ) { if ( name . toLowerCase ( ) . substr ( name . length - 4 ) === 'line' ) { iconSvg = faLine [ name . substr ( 2 ) ] ; } else if ( name . toLowerCase ( ) . substr ( name . length - 4 ) === 'fill' ) { iconSvg = faFill [ name . substr ( 2 ) ] ; } else { iconSvg = faBrands [ name . substr ( 2 ) ] ; } } else if ( prefix === 'Ri' ) { iconSvg = remixicons [ name . substr ( 2 ) ] ; } return iconSvg ; } ; public param { IconFolderPlugin } plugin param { string } icon param { HTMLElement } el returns { string } export const customizeIconStyle = ( plugin , icon , el ) : string => { const sizeRe = new RegExp ( /width="\d+" height="\d+"/g ) ; if ( icon . match ( sizeRe ) ) { icon = icon . replace ( sizeRe , `width="${ plugin . getSettings ( ) . fontSize }" height="${ plugin . getSettings ( ) . fontSize }"` ) ; } else { const sizeRe = new RegExp ( /width="\d+px" height="\d+px"/g ) ; icon = icon . replace ( sizeRe , `width="${ plugin . getSettings ( ) . fontSize }px" height="${ plugin . getSettings ( ) . fontSize }px"` ) ; } const colorRe = new RegExp ( /fill="(\w|#)+"/g ) ; icon = icon . replace ( colorRe , `fill="${ plugin . getSettings ( ) . iconColor ?? 'currentColor' }"` ) ; if ( plugin . getSettings ( ) . extraPadding ) { el . style . padding = `${ plugin . getSettings ( ) . extraPadding . top ?? 2 }px ${ plugin . getSettings ( ) . extraPadding . right ?? 2 }px ${ plugin . getSettings ( ) . extraPadding . bottom ?? 2 }px ${ plugin . getSettings ( ) . extraPadding . left ?? 2 }px` ; } return icon ; } ; public param { IconFolderPlugin } plugin param { [ string , string | FolderIconObject ] [ ] } data param { WeakMap < ExplorerLeaf , boolean > } registeredFileExplorers export const addIconsToDOM = ( plugin , data , registeredFileExplorers , callback ? ) : void => { const fileExplorers = plugin . app . workspace . getLeavesOfType ( 'file-explorer' ) ; fileExplorers . forEach ( ( fileExplorer ) => { if ( registeredFileExplorers . has ( fileExplorer ) ) { return ; } registeredFileExplorers . set ( fileExplorer , true ) ; const registeredFilePaths = { } ; data . forEach ( ( [ path ] ) => { registeredFilePaths [ path ] = true ; } ) ; data . forEach ( ( [ dataPath , value ] ) => { const fileItem = fileExplorer . view . fileItems [ dataPath ] ; if ( fileItem ) { const titleEl = fileItem . titleEl ; const titleInnerEl = fileItem . titleInnerEl ; if ( titleEl . children . length === 2 || titleEl . children . length === 1 ) { const iconName = typeof value === 'string' ? value : value . iconName ; if ( iconName ) { const iconNode = titleEl . createDiv ( ) ; iconNode . classList . add ( 'obsidian-icon-folder-icon' ) ; insertIconToNode ( plugin , iconName , iconNode ) ; titleEl . insertBefore ( iconNode , titleInnerEl ) ; } if ( typeof value === 'object' && value . inheritanceIcon ) { const files = plugin . app . vault . getFiles ( ) . filter ( ( f ) => f . path . includes ( dataPath ) ) ; const inheritanceIconName = value . inheritanceIcon ; files . forEach ( ( f ) => { if ( ! registeredFilePaths [ f . path ] ) { const inheritanceFileItem = fileExplorer . view . fileItems [ f . path ] ; const iconNode = inheritanceFileItem . titleEl . createDiv ( ) ; iconNode . classList . add ( 'obsidian-icon-folder-icon' ) ; insertIconToNode ( plugin , inheritanceIconName , iconNode ) ; inheritanceFileItem . titleEl . insertBefore ( iconNode , inheritanceFileItem . titleInnerEl ) ; } } ) ; } } } } ) ; if ( callback ) { callback ( ) ; } } ) ; } ; export const addInheritanceIconToFile = ( plugin , registeredFileExplorers , filePath , iconName ) : void => { const fileExplorers = plugin . app . workspace . getLeavesOfType ( 'file-explorer' ) ; fileExplorers . forEach ( ( fileExplorer ) => { if ( registeredFileExplorers . has ( fileExplorer ) ) { const fileItem = fileExplorer . view . fileItems [ filePath ] ; if ( fileItem ) { const iconNode = fileItem . titleEl . createDiv ( ) ; iconNode . classList . add ( 'obsidian-icon-folder-icon' ) ; insertIconToNode ( plugin , iconName , iconNode ) ; fileItem . titleEl . insertBefore ( iconNode , fileItem . titleInnerEl ) ; } } } ) ; } ; public param { IconFolderPlugin } plugin export const refreshIconStyle = ( plugin ) : void => { const data = Object . entries ( plugin . getData ( ) ) as [ string , string ] ; const fileExplorers = plugin . app . workspace . getLeavesOfType ( 'file-explorer' ) ; fileExplorers . forEach ( ( fileExplorer ) => { data . forEach ( ( [ key ] ) => { const fileItem = fileExplorer . view . fileItems [ key ] ; if ( fileItem ) { const titleEl = fileItem . titleEl ; const iconNode = titleEl . querySelector ( '.obsidian-icon-folder-icon' ) as HTMLElement ; iconNode . innerHTML = customizeIconStyle ( plugin , iconNode . innerHTML , iconNode ) ; } } ) ; } ) ; } ; public param { string } path export const removeFromDOM = ( path ) : void => { const node = document . querySelector ( `[data-path="${ path }"]` ) ; if ( ! node ) { console . error ( 'element with data path not found' , path ) ; return ; } const iconNode = node . querySelector ( '.obsidian-icon-folder-icon' ) ; if ( ! iconNode ) { return ; } iconNode . remove ( ) ; } ; public param { IconFolderPlugin } plugin param { string } path param { string } icon export const addToDOM = ( plugin , path , icon ) : void => { if ( plugin . getData ( ) [ path ] ) { removeFromDOM ( path ) ; } const node = document . querySelector ( `[data-path="${ path }"]` ) ; if ( ! node ) { console . error ( 'element with data path not found' , path ) ; return ; } let titleNode = node . querySelector ( '.nav-folder-title-content' ) ; if ( ! titleNode ) { titleNode = node . querySelector ( '.nav-file-title-content' ) ; if ( ! titleNode ) { console . error ( 'element with title not found' ) ; return ; } } const possibleInheritanceIcon = node . querySelector ( '.obsidian-icon-folder-icon' ) ; if ( possibleInheritanceIcon ) { possibleInheritanceIcon . remove ( ) ; } const iconNode = document . createElement ( 'div' ) ; iconNode . classList . add ( 'obsidian-icon-folder-icon' ) ; insertIconToNode ( plugin , icon , iconNode ) ; node . insertBefore ( iconNode , titleNode ) ; } ; param { IconFolderPlugin } plugin param { string } icon param { HTMLElement } node const insertIconToNode = ( plugin , icon , node ) : void => { if ( icon . substring ( 0 , 4 ) === 'RiRi' ) { icon = icon . substring ( 2 ) ; } const possibleIcon = getIcon ( icon ) ; if ( possibleIcon ) { node . innerHTML = customizeIconStyle ( plugin , possibleIcon , node ) ; } else { const emoji = twemoji . parse ( icon , { folder : 'svg' , ext : '.svg' , attributes : ( ) => ( { width : '16px' , height : '16px' , } ) , } ) ; node . innerHTML = customizeIconStyle ( plugin , emoji , node ) ; } } ; param { IconFolderPlugin } plugin param { string } folderPath export const addInheritanceForFolder = ( plugin , folderPath ) : void => { const folder = plugin . getData ( ) [ folderPath ] ; if ( ! folder || typeof folder !== 'object' ) { return ; } const files = plugin . app . vault . getFiles ( ) . filter ( ( f ) => f . path . includes ( folderPath ) ) ; files . forEach ( ( f ) => { if ( plugin . getData ( ) [ f . path ] ) { removeFromDOM ( f . path ) ; plugin . removeFolderIcon ( f . path ) ; } addToDOM ( plugin , f . path , ( folder as any ) . inheritanceIcon ) ; } ) ; } ; param { IconFolderPlugin } plugin param { string } folderPath export const removeInheritanceForFolder = ( plugin , folderPath ) : void => { const folder = plugin . getData ( ) [ folderPath ] ; if ( ! folder || typeof folder !== 'object' ) { return ; } const files = plugin . app . vault . getFiles ( ) . filter ( ( f ) => f . path . includes ( folderPath ) ) ; files . forEach ( ( f ) => { if ( ! plugin . getData ( ) [ f . path ] ) { removeFromDOM ( f . path ) ; } } ) ; } ; export const isEmoji = ( str ) : boolean => { const ranges = [ '(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c[\ude32-\ude3a]|[\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])' , ] ; if ( str . match ( ranges . join ( '|' ) ) ) { return true ; } else { return false ; } } ;