ae66c2e34c
Add 50,000+ icon font package sourced from Flaticon API with local webfonts and interactive icon explorer. Features: - 50,492 icons across 15 style variations (weight × corner) - Self-hosted webfonts (TTF, WOFF, WOFF2) - Interactive icon explorer with search and filters - FontForge-based build pipeline for generating fonts from SVGs - Drop-in CSS with class-based icon usage Build scripts: - scripts/build-font.py - Standalone FontForge Python script - build-fonts.js - Node.js orchestrator for font generation - update-icon-list.js - Fetch icon metadata from Flaticon API - build-icons-js.js - Generate browser-ready icon dataset Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Co-Authored-By: Z.ai GLM 4.7 <noreply@z.ai>
121 lines
3.6 KiB
JavaScript
121 lines
3.6 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
const https = require('https');
|
|
const buildIconsJs = require('./build-icons-js');
|
|
|
|
const API_URL = 'https://www.flaticon.com/ajax/icon-fonts-most-downloaded/';
|
|
const HEADERS = {
|
|
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
|
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
|
|
'Accept-Language': 'en-US,en;q=0.9',
|
|
'Sec-Ch-Ua': '"Not A(Brand";v="99", "Google Chrome";v="121"',
|
|
'Sec-Ch-Ua-Mobile': '?0',
|
|
'Sec-Ch-Ua-Platform': '"macOS"',
|
|
'Sec-Fetch-Dest': 'document',
|
|
'Sec-Fetch-Mode': 'navigate',
|
|
'Sec-Fetch-Site': 'none'
|
|
};
|
|
|
|
function parseArgs(argv) {
|
|
const args = {};
|
|
for (let i = 0; i < argv.length; i += 1) {
|
|
const arg = argv[i];
|
|
if (!arg.startsWith('--')) continue;
|
|
const key = arg.slice(2);
|
|
const value = argv[i + 1] && !argv[i + 1].startsWith('--') ? argv[i + 1] : true;
|
|
if (value !== true) i += 1;
|
|
args[key] = value;
|
|
}
|
|
return args;
|
|
}
|
|
|
|
function sleep(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
function fetchJson(page) {
|
|
const url = `${API_URL}${page}`;
|
|
return new Promise((resolve, reject) => {
|
|
const request = https.request(url, { headers: HEADERS }, response => {
|
|
let data = '';
|
|
response.on('data', chunk => {
|
|
data += chunk;
|
|
});
|
|
response.on('end', () => {
|
|
try {
|
|
resolve(JSON.parse(data));
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
});
|
|
});
|
|
|
|
request.on('error', reject);
|
|
request.end();
|
|
});
|
|
}
|
|
|
|
async function run() {
|
|
const args = parseArgs(process.argv.slice(2));
|
|
const start = Number(args.start || 1);
|
|
let end = Number(args.end || 0);
|
|
const delay = Number(args.delay || 100);
|
|
|
|
if (Number.isNaN(start) || start < 1) {
|
|
throw new Error('Invalid --start value');
|
|
}
|
|
|
|
console.log(`Fetching icons starting at page ${start}...`);
|
|
const first = await fetchJson(start);
|
|
if (!first || !Array.isArray(first.items)) {
|
|
throw new Error('Unexpected response from Flaticon API');
|
|
}
|
|
|
|
if (!end || Number.isNaN(end)) {
|
|
end = Number(first.pages || start);
|
|
}
|
|
|
|
const itemsById = new Map();
|
|
const addItems = items => {
|
|
(items || []).forEach(item => {
|
|
if (item && item.id) {
|
|
itemsById.set(item.id, item);
|
|
}
|
|
});
|
|
};
|
|
|
|
addItems(first.items);
|
|
console.log(`Page ${start}/${end}: ${first.items.length} items`);
|
|
|
|
for (let page = start + 1; page <= end; page += 1) {
|
|
const payload = await fetchJson(page);
|
|
addItems(payload.items);
|
|
if (page % 25 === 0 || page === end) {
|
|
console.log(`Page ${page}/${end}: ${payload.items.length} items`);
|
|
}
|
|
if (delay > 0) {
|
|
await sleep(delay);
|
|
}
|
|
}
|
|
|
|
const outputDir = path.join(__dirname, 'data');
|
|
if (!fs.existsSync(outputDir)) {
|
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
}
|
|
|
|
const allIcons = Array.from(itemsById.values());
|
|
const outputPath = path.join(outputDir, 'all_icons.json');
|
|
fs.writeFileSync(outputPath, JSON.stringify(allIcons), 'utf8');
|
|
console.log(`Wrote ${outputPath} (${allIcons.length} icons)`);
|
|
|
|
buildIconsJs({
|
|
inputPath: outputPath,
|
|
outputPath: path.join(outputDir, 'all_icons.js')
|
|
});
|
|
}
|
|
|
|
run().catch(error => {
|
|
console.error(error.message || error);
|
|
process.exit(1);
|
|
});
|