Format directories
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,3 +10,4 @@ coverage
|
||||
stats
|
||||
*.log
|
||||
packages/**/src/icons/*.js
|
||||
packages/**/src/icons/*.ts
|
||||
|
||||
2
packages/lucide-angular/.gitignore
vendored
2
packages/lucide-angular/.gitignore
vendored
@@ -48,4 +48,4 @@ Thumbs.db
|
||||
|
||||
#npm-yarn
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
src/createElement.js
|
||||
|
||||
15
packages/lucide-angular/LICENSE
Normal file
15
packages/lucide-angular/LICENSE
Normal file
@@ -0,0 +1,15 @@
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2020, Lucide Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
@@ -1,40 +1,40 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"newProjectRoot": "",
|
||||
"projects": {
|
||||
"lucide-angular": {
|
||||
"projectType": "library",
|
||||
"root": "projects/lucide-angular",
|
||||
"sourceRoot": "projects/lucide-angular/src",
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "projects/lucide-angular/tsconfig.lib.json",
|
||||
"project": "projects/lucide-angular/ng-package.json"
|
||||
"tsConfig": "tsconfig.lib.json",
|
||||
"project": "ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "projects/lucide-angular/tsconfig.lib.prod.json"
|
||||
"tsConfig": "tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "projects/lucide-angular/src/test.ts",
|
||||
"tsConfig": "projects/lucide-angular/tsconfig.spec.json",
|
||||
"karmaConfig": "projects/lucide-angular/karma.conf.js"
|
||||
"main": "src/test.ts",
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"projects/lucide-angular/tsconfig.lib.json",
|
||||
"projects/lucide-angular/tsconfig.spec.json"
|
||||
"tsconfig.lib.json",
|
||||
"tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies, global-require, func-names */
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
process.env.CHROME_BIN = require('puppeteer').executablePath();
|
||||
|
||||
module.exports = function (config) {
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
@@ -11,7 +12,7 @@ module.exports = function (config) {
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
],
|
||||
client: {
|
||||
jasmine: {
|
||||
@@ -20,18 +21,15 @@ module.exports = function (config) {
|
||||
// for example, you can disable the random execution with `random: false`
|
||||
// or set a specific seed with `seed: 4321`
|
||||
},
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true // removes the duplicated traces
|
||||
suppressAll: true, // removes the duplicated traces
|
||||
},
|
||||
coverageReporter: {
|
||||
dir: require('path').join(__dirname, '../../coverage/lucide-angular'),
|
||||
subdir: '.',
|
||||
reporters: [
|
||||
{ type: 'html' },
|
||||
{ type: 'text-summary' }
|
||||
]
|
||||
reporters: [{ type: 'html' }, { type: 'text-summary' }],
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
@@ -42,10 +40,10 @@ module.exports = function (config) {
|
||||
customLaunchers: {
|
||||
ChromeHeadlessCI: {
|
||||
base: 'ChromeHeadless',
|
||||
flags: ['--no-sandbox']
|
||||
}
|
||||
flags: ['--no-sandbox'],
|
||||
},
|
||||
},
|
||||
singleRun: false,
|
||||
restartOnFileChange: true
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
};
|
||||
7
packages/lucide-angular/ng-package.json
Normal file
7
packages/lucide-angular/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "./node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "dist",
|
||||
"lib": {
|
||||
"entryFile": "src/lucide.ts"
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lucide-icons/lucide.git",
|
||||
"directory": "packages/lucide-vue"
|
||||
"directory": "packages/lucide-angular"
|
||||
},
|
||||
"keywords": [
|
||||
"Lucide",
|
||||
@@ -22,11 +22,9 @@
|
||||
"Font Awesome"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "yarn clean && yarn build:js && yarn build:icons && yarn build:iconsindex && yarn build:ng",
|
||||
"clean": "rm -rf dist && rm -rf projects/lucide-angular/build",
|
||||
"build:js": "mkdir -p projects/lucide-angular/build && cp -av ../lucide/src/createElement.js projects/lucide-angular/build/",
|
||||
"build:icons": "yarn --cwd ../../ build:icons --output=../packages/lucide-angular/projects/lucide-angular/build --templateSrc=../packages/lucide-angular/scripts/exportTemplate && for f in projects/lucide-angular/build/icons/*.js; do mv -- \"$f\" \"${f%.js}.ts\"; done",
|
||||
"build:iconsindex": "yarn --cwd ../../ babel-node packages/lucide-angular/scripts/buildIconsIndex.js",
|
||||
"build": "yarn clean && yarn build:icons && yarn build:ng",
|
||||
"clean": "rm -rf dist && rm -rf ./src/icons/*.ts",
|
||||
"build:icons": "yarn --cwd ../../ build:icons --output=../packages/lucide-angular/src --templateSrc=../packages/lucide-angular/scripts/exportTemplate --iconFileExtention=.ts --exportFileName=index.ts",
|
||||
"build:ng": "ng build --prod",
|
||||
"test:headless": "ng test --no-watch --no-progress --browsers=ChromeHeadlessCI",
|
||||
"test": "ng test",
|
||||
@@ -34,14 +32,18 @@
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^11.2.6",
|
||||
"@angular/core": "^11.2.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/common": "~11.2.6",
|
||||
"@angular/compiler": "~11.2.6",
|
||||
"@angular/core": "~11.2.6",
|
||||
"@angular/platform-browser": "~11.2.6",
|
||||
"@angular/platform-browser-dynamic": "~11.2.6",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.1102.5",
|
||||
"@angular/cli": "~11.2.5",
|
||||
"@angular/compiler-cli": "~11.2.6",
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export * from './build/icons-index';
|
||||
|
||||
import * as icons from './build/icons-index';
|
||||
export { icons };
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"ngPackage": {
|
||||
"lib": {
|
||||
"entryFile": "../icons-index.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
export * from './src/lib/lucide-angular.component';
|
||||
export * from './src/lib/lucide-angular.module';
|
||||
export * from './lucide';
|
||||
@@ -1,10 +0,0 @@
|
||||
export type IconNode = readonly [string, object];
|
||||
export type IconData = readonly [string, object, IconNode[] ];
|
||||
|
||||
export declare const icons: { [key: string]: IconData };
|
||||
|
||||
import { default as createElementTmp } from './build/createElement';
|
||||
|
||||
export function createElement(ico: IconData): HTMLElement {
|
||||
return createElementTmp(ico as any);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../dist/lucide-angular",
|
||||
"lib": {
|
||||
"entryFile": "./lib-index.ts"
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"name": "lucide-angular",
|
||||
"description": "Lucide Angular package, Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.",
|
||||
"version": "0.15.0",
|
||||
"author": "SMAH1",
|
||||
"license": "ISC",
|
||||
"homepage": "https://lucide.dev",
|
||||
"bugs": "https://github.com/lucide-icons/lucide/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lucide-icons/lucide.git",
|
||||
"directory": "packages/lucide-vue"
|
||||
},
|
||||
"keywords": [
|
||||
"Lucide",
|
||||
"Angular",
|
||||
"Feather",
|
||||
"Icons",
|
||||
"Icon",
|
||||
"Feather Icons",
|
||||
"Fontawesome",
|
||||
"Font Awesome"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^11.2.6",
|
||||
"@angular/core": "^11.2.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"extends": "../../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"lib",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import path from 'path';
|
||||
|
||||
import {
|
||||
writeFile,
|
||||
resetFile,
|
||||
appendFile,
|
||||
readSvgDirectory,
|
||||
} from '../../../scripts/helpers';
|
||||
|
||||
const TARGET_DIR = path.join(__dirname, '../projects/lucide-angular/build');
|
||||
const ICONS_DIR = path.resolve(__dirname, '../../../icons');
|
||||
const TYPES_FILE_NAME = 'icons-index.ts';
|
||||
|
||||
// Generates header of d.ts file include some types and functions
|
||||
const typeDefinitions = `\
|
||||
export type IconNode = readonly [string, object];
|
||||
export type IconData = readonly [string, object, IconNode[] ];
|
||||
|
||||
export declare const icons: { [key: string]: IconData };
|
||||
|
||||
// Generated icons
|
||||
`;
|
||||
|
||||
resetFile(TYPES_FILE_NAME, TARGET_DIR);
|
||||
writeFile(typeDefinitions, TYPES_FILE_NAME, TARGET_DIR);
|
||||
|
||||
const svgFiles = readSvgDirectory(ICONS_DIR);
|
||||
|
||||
svgFiles.forEach(svgFile => {
|
||||
const kebab = path.basename(svgFile, '.svg');
|
||||
|
||||
appendFile(
|
||||
`export * from './icons/${kebab}';\n`,
|
||||
TYPES_FILE_NAME,
|
||||
TARGET_DIR,
|
||||
);
|
||||
});
|
||||
|
||||
console.log(`Generated ${TYPES_FILE_NAME} file with`, svgFiles.length, 'icons');
|
||||
@@ -1,10 +1,12 @@
|
||||
export default ({ componentName, children }) => `
|
||||
import { IconData } from '../../lucide';
|
||||
import defaultAttributes from '../../default-attributes';
|
||||
import { IconData } from './types';
|
||||
import defaultAttributes from './constants/default-attributes';
|
||||
|
||||
export const ${componentName}: IconData = [
|
||||
const ${componentName}: IconData = [
|
||||
'svg',
|
||||
defaultAttributes,
|
||||
${JSON.stringify(children)}
|
||||
];
|
||||
|
||||
export default ${componentName};
|
||||
`;
|
||||
|
||||
26
packages/lucide-angular/src/create-element.ts
Normal file
26
packages/lucide-angular/src/create-element.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { IconData } from './icons/types'
|
||||
|
||||
/**
|
||||
* Creates a new SVGElement from icon node
|
||||
* @param {string} tag
|
||||
* @param {object} attrs
|
||||
* @param {array} children
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
export const createElement = ([tag, attrs, children = []]: IconData): SVGElement => {
|
||||
const element = document.createElementNS('http://www.w3.org/2000/svg', tag);
|
||||
|
||||
Object.keys(attrs).forEach(name => {
|
||||
element.setAttribute(name, attrs[name]);
|
||||
});
|
||||
|
||||
if (children.length) {
|
||||
children.forEach((child: IconData) => {
|
||||
const childElement = createElement(child);
|
||||
|
||||
element.appendChild(childElement);
|
||||
});
|
||||
}
|
||||
|
||||
return element;
|
||||
};
|
||||
8
packages/lucide-angular/src/icons/package.json
Normal file
8
packages/lucide-angular/src/icons/package.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"ngPackage": {
|
||||
"dest": "dist",
|
||||
"lib": {
|
||||
"entryFile": "./index.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
3
packages/lucide-angular/src/icons/types/index.ts
Normal file
3
packages/lucide-angular/src/icons/types/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export type IconNode = readonly [string, object];
|
||||
export type IconData = readonly [string, object, IconNode[]? ];
|
||||
export type Icons = { [key: string]: IconData }
|
||||
@@ -1,3 +1,3 @@
|
||||
export class Icons {
|
||||
constructor(private icons: object) {}
|
||||
}
|
||||
export class Icons {
|
||||
constructor(private icons: object) {}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { LucideAngularModule } from './lucide-angular.module';
|
||||
|
||||
import { LucideAngularComponent } from './lucide-angular.component';
|
||||
|
||||
describe('LucideAngularComponent', () => {
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component, ElementRef, Input, Inject, ChangeDetectorRef, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { Icons } from './icons.provider';
|
||||
import { createElement, IconData } from '../../lucide';
|
||||
import { IconData } from '../icons/types';
|
||||
import { createElement } from '../create-element';
|
||||
|
||||
@Component({
|
||||
selector: 'lucide-angular, lucide-icon, i-lucide, span-lucide',
|
||||
@@ -16,6 +17,7 @@ import { createElement, IconData } from '../../lucide';
|
||||
}
|
||||
`]
|
||||
})
|
||||
|
||||
export class LucideAngularComponent implements OnChanges {
|
||||
@Input() name!: string;
|
||||
@Input() img!: IconData;
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NgModule, ModuleWithProviders, Optional } from '@angular/core';
|
||||
import { LucideAngularComponent } from './lucide-angular.component';
|
||||
import { Icons } from './icons.provider';
|
||||
import { IconData } from '../../lucide';
|
||||
import { IconData } from '../icons/types';
|
||||
|
||||
@NgModule({
|
||||
declarations: [LucideAngularComponent],
|
||||
8
packages/lucide-angular/src/lucide.ts
Normal file
8
packages/lucide-angular/src/lucide.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import * as icons from './icons';
|
||||
|
||||
export * from './lib/lucide-angular.component';
|
||||
export * from './lib/lucide-angular.module';
|
||||
export * from './icons';
|
||||
export * from './create-element';
|
||||
|
||||
export { icons };
|
||||
@@ -11,10 +11,10 @@
|
||||
"experimentalDecorators": true,
|
||||
"allowJs": true,
|
||||
"paths": {
|
||||
"lucide-angular": [
|
||||
"dist/lucide-angular/lucide-angular",
|
||||
"dist/lucide-angular"
|
||||
]
|
||||
// "lucide-angular": [
|
||||
// "dist"
|
||||
// ],
|
||||
"@/*": ["./src/*"],
|
||||
},
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../out-tsc/lib",
|
||||
"outDir": "./out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
@@ -1,8 +1,8 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../out-tsc/spec",
|
||||
"outDir": "./out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
@@ -16,6 +16,18 @@
|
||||
"deprecation": {
|
||||
"severity": "warning"
|
||||
},
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"lib",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"",
|
||||
"kebab-case"
|
||||
],
|
||||
"eofline": true,
|
||||
"import-blacklist": [
|
||||
true,
|
||||
|
||||
@@ -4,7 +4,7 @@ import path from 'path';
|
||||
import prettier from 'prettier';
|
||||
import { toPascalCase } from '../helpers';
|
||||
|
||||
export default function(iconNodes, outputDirectory, template, { showLog = true }) {
|
||||
export default function({ iconNodes, outputDirectory, template, showLog = true, iconFileExtention = '.js' }) {
|
||||
const icons = Object.keys(iconNodes);
|
||||
const iconsDistDirectory = path.join(outputDirectory, `icons`);
|
||||
|
||||
@@ -13,7 +13,7 @@ export default function(iconNodes, outputDirectory, template, { showLog = true }
|
||||
}
|
||||
|
||||
icons.forEach(iconName => {
|
||||
const location = path.join(iconsDistDirectory, `${iconName}.js`);
|
||||
const location = path.join(iconsDistDirectory, `${iconName}${iconFileExtention}`);
|
||||
const componentName = toPascalCase(iconName);
|
||||
|
||||
let { children } = iconNodes[iconName];
|
||||
|
||||
@@ -12,22 +12,38 @@ const cliArguments = getArgumentOptions(process.argv.slice(2));
|
||||
|
||||
const ICONS_DIR = path.resolve(__dirname, '../icons');
|
||||
const OUTPUT_DIR = path.resolve(__dirname, cliArguments.output || '../build');
|
||||
const SRC_DIR = path.resolve(__dirname, '../src');
|
||||
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR);
|
||||
}
|
||||
|
||||
const {
|
||||
renderUniqueKey = false,
|
||||
templateSrc = './templates/defaultIconFileTemplate',
|
||||
silent = false,
|
||||
iconFileExtention = '.js',
|
||||
exportFileName = 'index.js',
|
||||
} = cliArguments;
|
||||
|
||||
const svgFiles = readSvgDirectory(ICONS_DIR);
|
||||
|
||||
const icons = renderIconsObject(svgFiles, ICONS_DIR, cliArguments.renderUniqueKey);
|
||||
const icons = renderIconsObject(svgFiles, ICONS_DIR, renderUniqueKey);
|
||||
|
||||
const defaultIconFileTemplate = './templates/defaultIconFileTemplate';
|
||||
// eslint-disable-next-line import/no-dynamic-require
|
||||
const iconFileTemplate = require(cliArguments.templateSrc || defaultIconFileTemplate).default;
|
||||
const iconFileTemplate = require(templateSrc).default;
|
||||
|
||||
// Generates iconsNodes files for each icon
|
||||
generateIconFiles(icons, OUTPUT_DIR, iconFileTemplate, { showLog: !cliArguments.silent });
|
||||
generateIconFiles({
|
||||
iconNodes: icons,
|
||||
outputDirectory: OUTPUT_DIR,
|
||||
template: iconFileTemplate,
|
||||
showLog: !silent,
|
||||
iconFileExtention,
|
||||
});
|
||||
|
||||
// Generates entry files for the compiler filled with icons exports
|
||||
generateExportsFile(path.join(SRC_DIR, 'icons/index.js'), path.join(OUTPUT_DIR, 'icons'), icons);
|
||||
generateExportsFile(
|
||||
path.join(OUTPUT_DIR, 'icons', exportFileName),
|
||||
path.join(OUTPUT_DIR, 'icons'),
|
||||
icons,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user