/// /// Copyright © 2016-2024 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// import { ResourcesService } from '@core/services/resources.service'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { isNotEmptyStr } from '@core/utils'; export const svgIcons: {[key: string]: string} = { 'google-logo': '', 'github-logo': '', 'facebook-logo': '', 'apple-logo': '', 'queues-list': '' + '' + '' + '' + '', trendz: '' }; export const svgIconsUrl: { [key: string]: string } = { windows: '/assets/windows.svg', macos: '/assets/macos.svg', linux: '/assets/linux.svg', docker: '/assets/docker.svg' }; const svgIconNamespaces: string[] = ['mdi']; const svgIconNames = [...Object.keys(svgIcons), ...Object.keys(svgIconsUrl)]; export const splitIconName = (iconName: string): [string, string] => { if (!iconName) { return ['', '']; } const parts = iconName.split(':'); switch (parts.length) { case 1: return ['', parts[0]]; case 2: return parts as [string, string]; default: throw Error(`Invalid icon name: "${iconName}"`); } }; export const isSvgIcon = (icon: string): boolean => { const [namespace, iconName] = splitIconName(icon); return svgIconNamespaces.includes(namespace) || svgIconNames.includes(iconName); }; export interface MaterialIcon { name: string; displayName?: string; tags: string[]; } export const iconByName = (icons: Array, name: string): MaterialIcon => icons.find(i => i.name === name); const searchIconTags = (icon: MaterialIcon, searchText: string): boolean => !!icon.tags.find(t => t.toUpperCase().includes(searchText.toUpperCase())); const searchIcons = (_icons: Array, searchText: string): Array => _icons.filter( i => i.name.toUpperCase().includes(searchText.toUpperCase()) || i.displayName.toUpperCase().includes(searchText.toUpperCase()) || searchIconTags(i, searchText) ); const getCommonMaterialIcons = (icons: Array, chunkSize: number): Array => icons.slice(0, chunkSize * 4); export const getMaterialIcons = (resourcesService: ResourcesService, chunkSize = 11, all = false, searchText: string): Observable => resourcesService.loadJsonResource>('/assets/metadata/material-icons.json', (icons) => { for (const icon of icons) { const iconName = splitIconName(icon.name)[1]; const words = iconName.replace(/[_\-]/g, ' ').split(' '); for (let i = 0; i < words.length; i++) { words[i] = words[i].charAt(0).toUpperCase() + words[i].slice(1); } icon.displayName = words.join(' '); } return icons; } ).pipe( map((icons) => { if (isNotEmptyStr(searchText)) { return searchIcons(icons, searchText); } else if (!all) { return getCommonMaterialIcons(icons, chunkSize); } else { return icons; } }), map((icons) => { const iconChunks: MaterialIcon[][] = []; for (let i = 0; i < icons.length; i += chunkSize) { const chunk = icons.slice(i, i + chunkSize); iconChunks.push(chunk); } return iconChunks; }) );