'use strict';
const SOCIAL_ICONS = {
telegram: { label: 'Telegram', color: '26A5E4' },
vk: { label: 'VK', color: '0077FF' },
github: { label: 'GitHub', color: '181717' },
gitverse: { label: 'GitVerse', color: '0077FF' },
email: { label: 'Email', color: 'F5C56B' },
site: { label: 'Сайт', color: '4FF3C8' },
youtube: { label: 'YouTube', color: 'FF0000' },
habr: { label: 'Habr', color: '65A3BE' },
};
function badgeUrl(baseUrl, { label, message, color }) {
const qs = new URLSearchParams({ label, message, color }).toString();
return `${baseUrl}/api/svg/badge?${qs}`;
}
function svgUrl(baseUrl, path, params) {
const qs = new URLSearchParams(params).toString();
return `${baseUrl}${path}?${qs}`;
}
/**
* options = {
* baseUrl, provider, username, theme,
* tagline, subtitle,
* socials: { telegram, vk, email, site, youtube, habr },
* skills: ['Node.js','React',...],
* sections: { banner, badges, stats, langs, repos, heatmap, footer },
* repoTargets: [{name, description, htmlUrl, language, stars}] // для витрины
* }
*/
function buildReadme(options) {
const {
baseUrl,
provider,
username,
theme = 'forge',
tagline = '',
subtitle = '',
socials = {},
skills = [],
sections = {},
repoTargets = [],
} = options;
const parts = [];
if (sections.banner) {
const bannerUrl = svgUrl(baseUrl, '/api/svg/banner', {
text: tagline || `Привет, я ${username}`,
sub: subtitle,
theme,
});
parts.push(`<p align="center"><img src="${bannerUrl}" alt="banner" /></p>`);
}
if (sections.badges) {
const socialBadges = Object.entries(socials)
.filter(([, v]) => v)
.map(([key, value]) => {
const meta = SOCIAL_ICONS[key] || { label: key, color: '4FF3C8' };
const url = badgeUrl(baseUrl, { label: meta.label, message: value, color: meta.color });
return `<img src="${url}" alt="${meta.label}" />`;
});
if (socialBadges.length) {
parts.push(`<p align="center">\n${socialBadges.join('\n')}\n</p>`);
}
}
if (skills.length) {
const skillBadges = skills
.map((s) => `<img src="${badgeUrl(baseUrl, { label: '', message: s, color: '20242C' })}" alt="${s}" />`)
.join(' ');
parts.push(`### 🛠️ Стек\n\n<p align="center">\n${skillBadges}\n</p>`);
}
if (sections.stats || sections.langs) {
const row = [];
if (sections.stats) {
row.push(
`<img src="${svgUrl(baseUrl, '/api/svg/stats', { username, provider, theme })}" alt="stats" />`
);
}
if (sections.langs) {
row.push(
`<img src="${svgUrl(baseUrl, '/api/svg/langs', { username, provider, theme })}" alt="langs" />`
);
}
parts.push(`<p align="center">\n${row.join('\n')}\n</p>`);
}
if (sections.heatmap) {
parts.push(
`<p align="center"><img src="${svgUrl(baseUrl, '/api/svg/heatmap', { username, provider, theme })}" alt="activity" /></p>`
);
}
if (sections.repos && repoTargets.length) {
const rows = repoTargets
.map(
(r) =>
`| [${r.name}](${r.htmlUrl}) | ${r.description || '—'} | ${r.language || '—'} | ⭐ ${r.stars || 0} |`
)
.join('\n');
parts.push(
`### 📌 Избранные репозитории\n\n| Проект | Описание | Язык | Звёзды |\n|---|---|---|---|\n${rows}`
);
}
if (sections.footer) {
parts.push(
[
'---',
'',
`<p align="center"><sub>Собрано с помощью <a href="${baseUrl}">ReadmeForge</a> — без ИИ, всё на собственном сервере.</sub></p>`,
].join('\n')
);
}
return parts.join('\n\n');
}
module.exports = { buildReadme };