gulpfile.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. const gulp = require('gulp'),
  2. cp = require('child_process'),
  3. glob = require('glob'),
  4. fs = require('fs'),
  5. path = require('path'),
  6. p = require('./package.json'),
  7. csv = require('csv-parser'),
  8. zip = require('gulp-zip'),
  9. svgo = require('gulp-svgo'),
  10. puppeteer = require('puppeteer'),
  11. outlineStroke = require('svg-outline-stroke'),
  12. iconfont = require('gulp-iconfont'),
  13. template = require('lodash.template'),
  14. sass = require('node-sass'),
  15. cleanCSS = require('clean-css'),
  16. argv = require('minimist')(process.argv.slice(2)),
  17. svgParse = require('parse-svg-path'),
  18. svgpath = require('svgpath'),
  19. svgr = require('@svgr/core').default;
  20. async function asyncForEach(array, callback) {
  21. for (let index = 0; index < array.length; index++) {
  22. await callback(array[index], index, array);
  23. }
  24. }
  25. const svgToPng = async (filePath, destination) => {
  26. filePath = path.join(__dirname, filePath);
  27. const htmlFilePath = path.join("file:", filePath);
  28. const browser = await puppeteer.launch();
  29. const page = await browser.newPage();
  30. await page.setViewport({
  31. height: 24,
  32. width: 24,
  33. deviceScaleFactor: 10
  34. });
  35. await page.goto(htmlFilePath);
  36. await page.screenshot({
  37. path: path.join(__dirname, destination),
  38. omitBackground: true,
  39. fullPage: true
  40. });
  41. await browser.close();
  42. return page;
  43. };
  44. const createScreenshot = async (filePath) => {
  45. try {
  46. filePath = path.join(__dirname, filePath);
  47. const fileName = filePath.replace('.svg', '');
  48. const htmlFilePath = path.join("file:", filePath);
  49. const browser = await puppeteer.launch();
  50. const page = await browser.newPage();
  51. await page.setViewport({
  52. height: 10,
  53. width: 10,
  54. deviceScaleFactor: 2
  55. });
  56. await page.goto(htmlFilePath);
  57. await page.screenshot({
  58. path: `${fileName}.png`,
  59. omitBackground: false,
  60. fullPage: true
  61. });
  62. await browser.close();
  63. } catch (error) {
  64. console.error(error);
  65. throw Error(error);
  66. }
  67. };
  68. const printChangelog = function (newIcons, modifiedIcons, renamedIcons, pretty = false) {
  69. if (newIcons.length > 0) {
  70. if (pretty) {
  71. console.log(`### ${newIcons.length} new icons:`);
  72. newIcons.forEach(function (icon, i) {
  73. console.log(`- \`${icon}\``);
  74. });
  75. } else {
  76. let str = '';
  77. str += `${newIcons.length} new icons: `;
  78. newIcons.forEach(function (icon, i) {
  79. str += `\`${icon}\``;
  80. if ((i + 1) <= newIcons.length - 1) {
  81. str += ', '
  82. }
  83. });
  84. console.log(str);
  85. }
  86. console.log('');
  87. }
  88. if (modifiedIcons.length > 0) {
  89. let str = '';
  90. str += `Fixed icons: `;
  91. modifiedIcons.forEach(function (icon, i) {
  92. str += `\`${icon}\``;
  93. if ((i + 1) <= modifiedIcons.length - 1) {
  94. str += ', '
  95. }
  96. });
  97. console.log(str);
  98. console.log('');
  99. }
  100. if (renamedIcons.length > 0) {
  101. console.log(`Renamed icons: `);
  102. renamedIcons.forEach(function (icon, i) {
  103. console.log(`- \`${icon[0]}\` renamed to \`${icon[1]}\``);
  104. });
  105. }
  106. };
  107. const generateIconsPreview = function (files, destFile, cb, columnsCount = 17, paddingOuter = 7) {
  108. const padding = 26,
  109. iconSize = 24;
  110. const iconsCount = files.length,
  111. rowsCount = Math.ceil(iconsCount / columnsCount),
  112. width = columnsCount * (iconSize + padding) + 2 * paddingOuter - padding,
  113. height = rowsCount * (iconSize + padding) + 2 * paddingOuter - padding;
  114. let svgContentSymbols = '',
  115. svgContentIcons = '',
  116. x = paddingOuter,
  117. y = paddingOuter;
  118. files.forEach(function (file, i) {
  119. let name = path.basename(file, '.svg');
  120. let svgFile = fs.readFileSync(file),
  121. svgFileContent = svgFile.toString();
  122. svgFileContent = svgFileContent
  123. .replace('<svg xmlns="http://www.w3.org/2000/svg"', `<symbol id="${name}"`)
  124. .replace(' width="24" height="24"', '')
  125. .replace('</svg>', '</symbol>')
  126. .replace(/\n\s+/g, '');
  127. svgContentSymbols += `\t${svgFileContent}\n`;
  128. svgContentIcons += `\t<use xlink:href="#${name}" x="${x}" y="${y}" width="${iconSize}" height="${iconSize}" />\n`;
  129. x += padding + iconSize;
  130. if (i % columnsCount === columnsCount - 1) {
  131. x = paddingOuter;
  132. y += padding + iconSize;
  133. }
  134. });
  135. const svgContent = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 ${width} ${height}" width="${width}" height="${height}" style="color: #354052"><rect x="0" y="0" width="${width}" height="${height}" fill="#fff"></rect>\n${svgContentSymbols}\n${svgContentIcons}\n</svg>`;
  136. fs.writeFileSync(destFile, svgContent);
  137. createScreenshot(destFile);
  138. cb();
  139. };
  140. //*********************************************************************************************
  141. gulp.task('iconfont-prepare', function (cb) {
  142. cp.exec('mkdir -p icons-outlined/ && rm -fd ./icons-outlined/* && mkdir -p && rm -fd ./iconfont/*', function () {
  143. cb();
  144. });
  145. });
  146. gulp.task('iconfont-clean', function (cb) {
  147. cp.exec('rm -rf ./icons-outlined', function () {
  148. cb();
  149. });
  150. });
  151. gulp.task('iconfont-svg-outline', function (cb) {
  152. cp.exec('mkdir -p icons-outlined/ && rm -fd ./icons-outlined/*', async () => {
  153. let files = glob.sync("./icons/*.svg");
  154. let iconfontUnicode = {};
  155. if (fs.existsSync('./.build/iconfont-unicode.json')) {
  156. iconfontUnicode = require('./.build/iconfont-unicode');
  157. }
  158. await asyncForEach(files, async function (file) {
  159. const name = path.basename(file, '.svg'),
  160. unicode = iconfontUnicode[name];
  161. await console.log('Stroke for:', file, unicode);
  162. let strokedSVG = fs.readFileSync(file).toString();
  163. strokedSVG = strokedSVG
  164. .replace('width="24"', 'width="1000"')
  165. .replace('height="24"', 'height="1000"');
  166. await outlineStroke(strokedSVG, {
  167. optCurve: false,
  168. steps: 4,
  169. round: 0,
  170. centerHorizontally: true,
  171. fixedWidth: true,
  172. color: 'black'
  173. }).then(outlined => {
  174. if (unicode) {
  175. fs.writeFileSync(`icons-outlined/u${unicode.toUpperCase()}-${name}.svg`, outlined);
  176. } else {
  177. fs.writeFileSync(`icons-outlined/${name}.svg`, outlined);
  178. }
  179. }).catch(error => console.log(error));
  180. });
  181. cb();
  182. });
  183. });
  184. gulp.task('iconfont-optimize', function() {
  185. return gulp.src('icons-outlined/*')
  186. .pipe(svgo())
  187. .pipe(gulp.dest('icons-outlined'));
  188. });
  189. gulp.task('iconfont-fix-outline', function(cb) {
  190. // correct svg outline directions in a child process using fontforge
  191. const generate = cp.spawn("fontforge", ["-lang=py", "-script", "./fix-outline.py"], { stdio: 'inherit' });
  192. generate.on("close", function (code) {
  193. console.log(`Correcting svg outline directions exited with code ${code}`);
  194. if (!code) {
  195. cb();
  196. }
  197. });
  198. });
  199. gulp.task('iconfont', function () {
  200. let maxUnicode = 59905;
  201. if (fs.existsSync('./.build/iconfont-unicode.json')) {
  202. const iconfontUnicode = require('./.build/iconfont-unicode');
  203. for (const name in iconfontUnicode) {
  204. const unicode = parseInt(iconfontUnicode[name], 16);
  205. maxUnicode = Math.max(maxUnicode, unicode);
  206. }
  207. }
  208. maxUnicode = maxUnicode + 1;
  209. return gulp.src(['icons-outlined/*.svg'])
  210. .pipe(iconfont({
  211. fontName: 'tabler-icons',
  212. prependUnicode: true,
  213. formats: ['ttf', 'eot', 'woff', 'woff2', 'svg'],
  214. normalize: true,
  215. startUnicode: maxUnicode,
  216. fontHeight: 1000,
  217. descent: 100,
  218. ascent: 986.5
  219. }))
  220. .on('glyphs', function (glyphs, options) {
  221. //glyphs json
  222. let glyphsObject = {};
  223. //sort glypht
  224. glyphs = glyphs.sort(function (a, b) {
  225. return ('' + a.name).localeCompare(b.name)
  226. });
  227. glyphs.forEach(function (glyph) {
  228. glyphsObject[glyph.name] = glyph.unicode[0].codePointAt(0).toString(16);
  229. });
  230. fs.writeFileSync(`./.build/iconfont-unicode.json`, JSON.stringify(glyphsObject));
  231. //css
  232. options['glyphs'] = glyphs;
  233. options['v'] = p.version;
  234. const compiled = template(fs.readFileSync('.build/iconfont.scss').toString());
  235. const result = compiled(options);
  236. fs.writeFileSync('iconfont/tabler-icons.scss', result);
  237. //html
  238. const compiledHtml = template(fs.readFileSync('.build/iconfont.html').toString());
  239. const resultHtml = compiledHtml(options);
  240. fs.writeFileSync('iconfont/tabler-icons.html', resultHtml);
  241. })
  242. .pipe(gulp.dest('iconfont/fonts'));
  243. });
  244. gulp.task('iconfont-css', function (cb) {
  245. sass.render({
  246. file: 'iconfont/tabler-icons.scss',
  247. outputStyle: 'expanded'
  248. }, function (err, result) {
  249. fs.writeFileSync('iconfont/tabler-icons.css', result.css);
  250. const cleanOutput = new cleanCSS({}).minify(result.css);
  251. fs.writeFileSync('iconfont/tabler-icons.min.css', cleanOutput.styles);
  252. cb();
  253. });
  254. });
  255. gulp.task('update-tags-unicode', function(cb) {
  256. let tags = require('./tags.json'),
  257. unicodes = require('./.build/iconfont-unicode.json');
  258. for(let i in tags) {
  259. tags[i] = {
  260. ...tags[i],
  261. unicode: unicodes[i],
  262. }
  263. }
  264. console.log('tags', tags);
  265. fs.writeFileSync(`tags.json`, JSON.stringify(tags, null, 2));
  266. cb();
  267. });
  268. gulp.task('build-iconfont', gulp.series('iconfont-prepare', 'iconfont-svg-outline', 'iconfont-fix-outline', 'iconfont-optimize', 'iconfont', 'iconfont-css', 'iconfont-clean', 'update-tags-unicode'));
  269. gulp.task('build-zip', function () {
  270. const version = p.version;
  271. return gulp.src('{icons/**/*,icons-png/**/*,icons-react/**/*,iconfont/**/*,tabler-sprite.svg,tabler-sprite-nostroke.svg}')
  272. .pipe(zip(`tabler-icons-${version}.zip`))
  273. .pipe(gulp.dest('packages'))
  274. });
  275. gulp.task('build-jekyll', function (cb) {
  276. cp.exec('bundle exec jekyll build', function () {
  277. cb();
  278. });
  279. });
  280. gulp.task('build-copy', function (cb) {
  281. cp.exec('mkdir -p icons/ && rm -fd ./icons/* && cp ./_site/icons/* ./icons && cp ./_site/tags.json .', function () {
  282. cb();
  283. });
  284. });
  285. gulp.task('clean-png', function (cb) {
  286. cp.exec('rm -fd ./icons-png/*', function () {
  287. cb();
  288. });
  289. });
  290. gulp.task('icons-sprite', function (cb) {
  291. glob("_site/icons/*.svg", {}, function (er, files) {
  292. let svgContent = '';
  293. files.forEach(function (file, i) {
  294. let name = path.basename(file, '.svg'),
  295. svgFile = fs.readFileSync(file),
  296. svgFileContent = svgFile.toString();
  297. svgFileContent = svgFileContent
  298. .replace(/<svg[^>]+>/g, '')
  299. .replace(/<\/svg>/g, '')
  300. .replace(/\n+/g, '')
  301. .replace(/>\s+</g, '><')
  302. .trim();
  303. svgContent += `<symbol id="tabler-${name}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${svgFileContent}</symbol>`
  304. });
  305. let svg = `<svg xmlns="http://www.w3.org/2000/svg"><defs>${svgContent}</defs></svg>`;
  306. fs.writeFileSync('tabler-sprite.svg', svg);
  307. fs.writeFileSync('tabler-sprite-nostroke.svg', svg.replace(/stroke-width="2"\s/g, ''));
  308. cb();
  309. });
  310. });
  311. gulp.task('icons-preview', function (cb) {
  312. glob("icons/*.svg", {}, function (er, files) {
  313. generateIconsPreview(files, '.github/icons.svg', cb);
  314. });
  315. });
  316. gulp.task('icons-stroke', gulp.series('build-jekyll', function (cb) {
  317. const icon = "disabled",
  318. strokes = ['.5', '1', '1.5', '2', '2.75'],
  319. svgFileContent = fs.readFileSync(`icons/${icon}.svg`).toString(),
  320. padding = 16,
  321. paddingOuter = 3,
  322. iconSize = 32,
  323. width = 914,
  324. height = iconSize + paddingOuter * 2;
  325. let svgContentSymbols = '',
  326. svgContentIcons = '',
  327. x = paddingOuter;
  328. strokes.forEach(function (stroke) {
  329. let svgFileContentStroked = svgFileContent
  330. .replace('<svg xmlns="http://www.w3.org/2000/svg"', `<symbol id="icon-${stroke}"`)
  331. .replace(' width="24" height="24"', '')
  332. .replace(' stroke-width="2"', ` stroke-width="${stroke}"`)
  333. .replace('</svg>', '</symbol>')
  334. .replace(/\n\s+/g, '');
  335. svgContentSymbols += `\t${svgFileContentStroked}\n`;
  336. svgContentIcons += `\t<use xlink:href="#icon-${stroke}" x="${x}" y="${paddingOuter}" width="${iconSize}" height="${iconSize}" />\n`;
  337. x += padding + iconSize;
  338. });
  339. const svgContent = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 ${width} ${height}" width="${width}" height="${height}" style="color: #354052"><rect x="0" y="0" width="${width}" height="${height}" fill="#fff"></rect>\n${svgContentSymbols}\n${svgContentIcons}\n</svg>`;
  340. fs.writeFileSync('.github/icons-stroke.svg', svgContent);
  341. createScreenshot('.github/icons-stroke.svg');
  342. cb();
  343. }));
  344. gulp.task('optimize', function (cb) {
  345. const addFloats = function (n1, n2) {
  346. return Math.round((parseFloat(n1) + parseFloat(n2)) * 1000) / 1000
  347. };
  348. const optimizePath = function(path) {
  349. let transformed = svgpath(path)
  350. .rel()
  351. .round(3)
  352. .toString();
  353. return svgParse(transformed).map(function(a){
  354. return a.join(' ');
  355. }).join(' ');
  356. };
  357. glob("src/_icons/*.svg", {}, function (er, files) {
  358. files.forEach(function (file, i) {
  359. let svgFile = fs.readFileSync(file),
  360. svgFileContent = svgFile.toString();
  361. svgFileContent = svgFileContent
  362. .replace(/><\/(polyline|line|rect|circle|path)>/g, '/>')
  363. .replace(/rx="([^"]+)"\s+ry="\1"/g, 'rx="$1"')
  364. .replace(/\s?\/>/g, ' />')
  365. .replace(/\n\s*<(line|circle|path|polyline|rect)/g, "\n <$1")
  366. .replace(/polyline points="([0-9.]+)\s([0-9.]+)\s([0-9.]+)\s([0-9.]+)"/g, 'line x1="$1" y1="$2" x2="$3" y2="$4"')
  367. .replace(/<path d="([^"]+)"/g, function(f, r1) {
  368. r1 = optimizePath(r1);
  369. return `<path d="${r1}"`;
  370. })
  371. .replace(/d="m/g, 'd="M')
  372. .replace(/([Aa])\s?([0-9.]+)\s([0-9.]+)\s([0-9.]+)\s?([0-1])\s?([0-1])\s?(-?[0-9.]+)\s?(-?[0-9.]+)/gi, '$1$2 $3 $4 $5 $6 $7 $8')
  373. .replace(/\n\n+/g, "\n")
  374. .replace(/<path d="M([0-9.]*) ([0-9.]*)l\s?([-0-9.]*) ([-0-9.]*)"/g, function (f, r1, r2, r3, r4) {
  375. return `<line x1="${r1}" y1="${r2}" x2="${addFloats(r1, r3)}" y2="${addFloats(r2, r4)}"`;
  376. })
  377. .replace(/<path d="M([0-9.]*) ([0-9.]*)v\s?([-0-9.]*)"/g, function (f, r1, r2, r3) {
  378. return `<line x1="${r1}" y1="${r2}" x2="${r1}" y2="${addFloats(r2, r3)}"`;
  379. })
  380. .replace(/<path d="M([0-9.]*) ([0-9.]*)h\s?([-0-9.]*)"/g, function (f, r1, r2, r3) {
  381. return `<line x1="${r1}" y1="${r2}" x2="${addFloats(r1, r3)}" y2="${r2}"`;
  382. })
  383. .replace(/<path d="([^"]+)"/g, function (f, r1) {
  384. r1 = r1
  385. .replace(/ -0\./g, " -.")
  386. .replace(/ 0\./g, " .")
  387. .replace(/\s([a-z])/gi, "$1")
  388. .replace(/([a-z])\s/gi, "$1");
  389. return `<path d="${r1}"`;
  390. })
  391. ;
  392. if (svgFile.toString() !== svgFileContent) {
  393. fs.writeFileSync(file, svgFileContent);
  394. }
  395. });
  396. cb();
  397. });
  398. });
  399. gulp.task('changelog-commit', function (cb) {
  400. cp.exec('git status', function (err, ret) {
  401. let newIcons = [], modifiedIcons = [], renamedIcons = [];
  402. ret.replace(/new file:\s+src\/_icons\/([a-z0-9-]+)\.svg/g, function (m, fileName) {
  403. newIcons.push(fileName);
  404. });
  405. ret.replace(/modified:\s+src\/_icons\/([a-z0-9-]+)\.svg/g, function (m, fileName) {
  406. modifiedIcons.push(fileName);
  407. });
  408. ret.replace(/renamed:\s+src\/_icons\/([a-z0-9-]+).svg -> src\/_icons\/([a-z0-9-]+).svg/g, function (m, fileNameBefore, fileNameAfter) {
  409. renamedIcons.push([fileNameBefore, fileNameAfter]);
  410. });
  411. modifiedIcons = modifiedIcons.filter(function (el) {
  412. return newIcons.indexOf(el) < 0;
  413. });
  414. printChangelog(newIcons, modifiedIcons, renamedIcons);
  415. cb();
  416. });
  417. });
  418. gulp.task('changelog', function (cb) {
  419. const version = argv['latest-tag'] || `v${p.version}`;
  420. if (version) {
  421. cp.exec(`git diff ${version} HEAD --name-status`, function (err, ret) {
  422. let newIcons = [], modifiedIcons = [], renamedIcons = [];
  423. ret.replace(/A\s+src\/_icons\/([a-z0-9-]+)\.svg/g, function (m, fileName) {
  424. newIcons.push(fileName);
  425. });
  426. ret.replace(/M\s+src\/_icons\/([a-z0-9-]+)\.svg/g, function (m, fileName) {
  427. modifiedIcons.push(fileName);
  428. });
  429. ret.replace(/R[0-9]+\s+src\/_icons\/([a-z0-9-]+)\.svg\s+src\/_icons\/([a-z0-9-]+).svg/g, function (m, fileNameBefore, fileNameAfter) {
  430. renamedIcons.push([fileNameBefore, fileNameAfter]);
  431. });
  432. modifiedIcons = modifiedIcons.filter(function (el) {
  433. return newIcons.indexOf(el) < 0;
  434. });
  435. printChangelog(newIcons, modifiedIcons, renamedIcons, true);
  436. cb();
  437. });
  438. }
  439. });
  440. gulp.task('changelog-image', function (cb) {
  441. const version = argv['latest-version'] || `${p.version}`,
  442. newVersion = argv['new-version'] || `${p.version}`;
  443. if (version) {
  444. cp.exec(`git diff v${version} HEAD --name-status`, function (err, ret) {
  445. let newIcons = [];
  446. ret.replace(/[A]\s+src\/_icons\/([a-z0-9-]+)\.svg/g, function (m, fileName) {
  447. newIcons.push(fileName);
  448. });
  449. newIcons = newIcons.map(function (icon) {
  450. return `./icons/${icon}.svg`;
  451. });
  452. if (newIcons.length > 0) {
  453. generateIconsPreview(newIcons, `.github/tabler-icons-${newVersion}.svg`, cb, 6, 24);
  454. } else {
  455. cb();
  456. }
  457. });
  458. } else {
  459. cb();
  460. }
  461. });
  462. gulp.task('svg-to-png', gulp.series('build-jekyll', 'clean-png', async (cb) => {
  463. let files = glob.sync("./icons/*.svg");
  464. await asyncForEach(files, async function (file, i) {
  465. let name = path.basename(file, '.svg');
  466. console.log('name', name);
  467. await svgToPng(file, `icons-png/${name}.png`);
  468. });
  469. cb();
  470. }));
  471. gulp.task('clean-react', function (cb) {
  472. cp.exec('rm -fd ./icons-react/* && mkdir icons-react/icons-js', function () {
  473. cb();
  474. });
  475. });
  476. gulp.task('svg-to-react', gulp.series('clean-react', async function (cb) {
  477. let files = glob.sync("./icons/*.svg");
  478. const camelize = function (str) {
  479. str = str.replace(/-/g, ' ');
  480. return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function (word, index) {
  481. return word.toUpperCase();
  482. }).replace(/\s+/g, '');
  483. };
  484. const componentName = function (file) {
  485. file = path.basename(file, '.svg');
  486. file = camelize(`Icon ${file}`);
  487. return file;
  488. };
  489. const optimizeSvgCode = function(svgCode) {
  490. return svgCode.replace('<path stroke="none" d="M0 0h24v24H0z"/>', '');
  491. };
  492. let indexCode = '',
  493. indexDCode = `import { FC, SVGAttributes } from 'react';\n\ninterface TablerIconProps extends SVGAttributes<SVGElement> { color?: string; size?: string | number; stroke?: string | number; }\n\ntype TablerIcon = FC<TablerIconProps>;\n\n`;
  494. await asyncForEach(files, async function (file) {
  495. const svgCode = optimizeSvgCode(fs.readFileSync(file).toString()),
  496. fileName = path.basename(file, '.svg') + '.js',
  497. iconComponentName = componentName(file);
  498. svgr(svgCode, {
  499. icon: false,
  500. svgProps: { width: '{size}', height: '{size}', strokeWidth: '{stroke}', stroke: '{color}' },
  501. template: require('./.build/svgr-template')
  502. }, { componentName: iconComponentName }).then(jsCode => {
  503. fs.writeFileSync('icons-react/icons-js/' + fileName, jsCode);
  504. indexCode += `export { default as ${iconComponentName} } from './icons-js/${fileName}';\n`;
  505. indexDCode += `export const ${iconComponentName}: TablerIcon;\n`;
  506. });
  507. fs.writeFileSync('icons-react/index.js', indexCode);
  508. fs.writeFileSync('icons-react/index.d.ts', indexDCode);
  509. });
  510. cb();
  511. }));
  512. const setVersions = function(version, files) {
  513. for(const i in files) {
  514. const file = files[i];
  515. if (fs.existsSync(`src/_icons/${file}.svg`)) {
  516. let svgFile = fs.readFileSync(`src/_icons/${file}.svg`).toString();
  517. if(!svgFile.match(/version: ([0-9.]+)/i)) {
  518. svgFile = svgFile.replace(/---\n<svg>/i, function(m){
  519. return `version: ${version}\n${m}`;
  520. });
  521. fs.writeFileSync(`src/_icons/${file}.svg`, svgFile);
  522. } else {
  523. console.log(`File ${file} already has version`);
  524. }
  525. } else {
  526. console.log(`File ${file} doesn't exists`);
  527. }
  528. }
  529. };
  530. gulp.task('update-icons-version', function (cb) {
  531. const version = argv['latest-version'] || `${p.version}`,
  532. newVersion = argv['new-version'] || `${p.version}`;
  533. if (version) {
  534. cp.exec(`git diff v${version} HEAD --name-status`, function (err, ret) {
  535. let newIcons = [];
  536. ret.replace(/[A]\s+src\/_icons\/([a-z0-9-]+)\.svg/g, function (m, fileName) {
  537. newIcons.push(fileName);
  538. });
  539. if(newIcons.length) {
  540. setVersions(newVersion.replace(/\.0$/, ''), newIcons);
  541. }
  542. });
  543. }
  544. cb();
  545. });
  546. gulp.task('import-tags', function(cb) {
  547. fs.createReadStream('./_import.csv')
  548. .pipe(csv({
  549. headers: false,
  550. separator: "\t"
  551. }))
  552. .on('data', (row) => {
  553. console.log(row[0], row[1]);
  554. const filename = `src/_icons/${row[0]}.svg`;
  555. let data = fs.readFileSync(filename).toString();
  556. data = data.replace(/(---[\s\S]+?---)/, function(m, headerContent){
  557. headerContent = headerContent.replace(/tags: .*\n/, '');
  558. headerContent = headerContent.replace(/---/, `---\ntags: [${row[1]}]`);
  559. return headerContent;
  560. });
  561. fs.writeFileSync(filename, data);
  562. })
  563. .on('end', () => {
  564. console.log('CSV file successfully processed');
  565. });
  566. cb();
  567. });
  568. gulp.task("build-react", function (cb) {
  569. cp.exec("npm run build-react", function () {
  570. cb();
  571. });
  572. });
  573. gulp.task('build', gulp.series('optimize', 'update-icons-version', 'build-jekyll', 'build-copy', 'icons-sprite', 'svg-to-react', 'build-react', 'icons-preview', 'svg-to-png', 'build-iconfont', 'changelog-image', 'build-zip'));