Skip to content

Commit 119a06e

Browse files
Доработки по png значкам
1 parent 1a5be37 commit 119a06e

7 files changed

Lines changed: 355 additions & 26 deletions

File tree

core/src/CommonModules/МетодыТелеграм/Module.bsl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@
305305

306306
Текст = Текст + Символы.ПС;
307307
Текст = Текст + "_Не забывайте поддерживать понравившиеся репозитории - от этого зависит их дальнейшее развитие!_";
308+
Текст = РаскодироватьСтроку(Текст, СпособКодированияСтроки.URLВКодировкеURL);
308309

309310
Токен = ИнструментарийВызовСервера.ПолучитьНастройку("ТокенТелеграм");
310311
Чат = ИнструментарийВызовСервера.ПолучитьНастройку("ЧатТелеграм");
@@ -331,6 +332,8 @@
331332
Картинка = ИнструментарийВызовСервера.ПолучитьФайл("Бусти");
332333

333334
Клавиатура = ПолучитьКлавиатуруБусти();
335+
336+
Текст = РаскодироватьСтроку(Текст, СпособКодированияСтроки.URLВКодировкеURL);
334337
Ответ = OPI_Telegram.ОтправитьКартинку(Токен, Чат, Текст, Картинка, Клавиатура);
335338

336339
Если Не Ответ["ok"] Тогда
@@ -342,7 +345,8 @@
342345

343346
Процедура ОпубликоватьБрошюру() Экспорт
344347

345-
Текст = ПолучитьОбщийМакет("СообщениеБрошюры").ПолучитьТекст();
348+
Текст = ПолучитьОбщийМакет("СообщениеБрошюры").ПолучитьТекст();
349+
Текст = РаскодироватьСтроку(Текст, СпособКодированияСтроки.URLВКодировкеURL);
346350

347351
Токен = ИнструментарийВызовСервера.ПолучитьНастройку("ТокенТелеграм");
348352
Чат = ИнструментарийВызовСервера.ПолучитьНастройку("ЧатТелеграм");

web/client/badges.html

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,13 @@ <h2>Как получить значок для своего репозитор
8787
2. Найдите свой репозиторий в таблице
8888
</p>
8989
<p style="margin-bottom: var(--spacing-md); color: var(--text-secondary);">
90-
3. В колонке "Значок" скопируйте Markdown разметку
90+
3. В колонке "Значок" нажмите кнопку для открытия окна с разметкой
9191
</p>
9292
<p style="margin-bottom: var(--spacing-md); color: var(--text-secondary);">
93-
4. Вставьте её в README.md вашего репозитория
93+
4. Выберите формат (SVG или PNG) и скопируйте Markdown разметку
94+
</p>
95+
<p style="margin-bottom: var(--spacing-md); color: var(--text-secondary);">
96+
5. Вставьте её в README.md вашего репозитория
9497
</p>
9598
</div>
9699
</div>
@@ -131,15 +134,25 @@ <h2>Зачем добавлять значок?</h2>
131134
</div>
132135

133136
<!-- Example -->
134-
<h2 class="section-title" style="margin-top: var(--spacing-xl);">Пример разметки</h2>
137+
<h2 class="section-title" style="margin-top: var(--spacing-xl);">Примеры разметки</h2>
135138

136139
<div class="badge-example">
137-
<h3>Пример Markdown для README.md</h3>
140+
<h3>SVG формат (рекомендуется)</h3>
138141
<div class="badge-code">
139142
[![OpenYellow](https://openyellow.openintegrations.dev/data/badges/736878759.svg)](https://openyellow.org/grid?filter=top&repo=736878759)
140143
</div>
141144
<p style="color: var(--text-secondary); margin-top: var(--spacing-md); font-size: 0.875rem;">
142-
Где <code>736878759</code> - это ID вашего репозитория. Значок генерируется динамически в формате SVG.
145+
SVG формат обеспечивает лучшее качество отображения на любых экранах.
146+
</p>
147+
</div>
148+
149+
<div class="badge-example" style="margin-top: var(--spacing-md);">
150+
<h3>PNG формат</h3>
151+
<div class="badge-code">
152+
[![OpenYellow](https://openyellow.openintegrations.dev/data/badges/736878759.png)](https://openyellow.org/grid?filter=top&repo=736878759)
153+
</div>
154+
<p style="color: var(--text-secondary); margin-top: var(--spacing-md); font-size: 0.875rem;">
155+
PNG формат для случаев, когда SVG не поддерживается. Где <code>736878759</code> - это ID вашего репозитория.
143156
</p>
144157
</div>
145158

web/client/css/main.css

Lines changed: 163 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2913,4 +2913,166 @@ img {
29132913
min-height: 200px;
29142914
max-height: 200px;
29152915
}
2916-
}
2916+
}
2917+
2918+
/* ===== Badge Button and Modal ===== */
2919+
.badge-btn {
2920+
padding: 4px 10px;
2921+
background-color: var(--bg-tertiary);
2922+
border: 1px solid var(--border-color);
2923+
border-radius: var(--radius-sm);
2924+
color: var(--text-secondary);
2925+
cursor: pointer;
2926+
transition: var(--transition);
2927+
font-size: 0.75rem;
2928+
white-space: nowrap;
2929+
}
2930+
2931+
.badge-btn:hover {
2932+
background-color: var(--accent-primary);
2933+
color: var(--bg-primary);
2934+
border-color: var(--accent-primary);
2935+
}
2936+
2937+
.badge-modal .modal-content {
2938+
max-width: 600px;
2939+
}
2940+
2941+
.badge-modal-content {
2942+
padding: var(--spacing-lg);
2943+
}
2944+
2945+
.badge-modal-content h2 {
2946+
margin: 0 0 var(--spacing-xs) 0;
2947+
font-size: 1.5rem;
2948+
}
2949+
2950+
.badge-modal-description {
2951+
color: var(--text-secondary);
2952+
margin-bottom: var(--spacing-lg);
2953+
font-size: 0.875rem;
2954+
}
2955+
2956+
.badge-format-section {
2957+
margin-bottom: var(--spacing-lg);
2958+
padding: var(--spacing-md);
2959+
background-color: var(--bg-tertiary);
2960+
border-radius: var(--radius-md);
2961+
border: 1px solid var(--border-color);
2962+
}
2963+
2964+
.badge-format-section:last-child {
2965+
margin-bottom: 0;
2966+
}
2967+
2968+
.badge-format-header {
2969+
display: flex;
2970+
justify-content: space-between;
2971+
align-items: center;
2972+
margin-bottom: var(--spacing-sm);
2973+
}
2974+
2975+
.badge-format-label {
2976+
font-weight: 600;
2977+
color: var(--text-primary);
2978+
font-size: 0.875rem;
2979+
}
2980+
2981+
.badge-preview-img {
2982+
height: 20px;
2983+
max-width: 150px;
2984+
}
2985+
2986+
.badge-code-row {
2987+
display: flex;
2988+
gap: var(--spacing-sm);
2989+
align-items: stretch;
2990+
}
2991+
2992+
.badge-modal-input {
2993+
flex: 1;
2994+
padding: var(--spacing-xs) var(--spacing-sm);
2995+
background-color: var(--bg-primary);
2996+
border: 1px solid var(--border-color);
2997+
border-radius: var(--radius-sm);
2998+
color: var(--text-primary);
2999+
font-size: 0.75rem;
3000+
font-family: monospace;
3001+
min-width: 0;
3002+
}
3003+
3004+
.badge-modal-input:focus {
3005+
outline: none;
3006+
border-color: var(--accent-primary);
3007+
}
3008+
3009+
.badge-copy-btn {
3010+
display: flex;
3011+
align-items: center;
3012+
gap: var(--spacing-xs);
3013+
padding: var(--spacing-xs) var(--spacing-md);
3014+
background-color: var(--accent-primary);
3015+
border: none;
3016+
border-radius: var(--radius-sm);
3017+
color: var(--bg-primary);
3018+
cursor: pointer;
3019+
transition: var(--transition);
3020+
font-size: 0.875rem;
3021+
font-weight: 600;
3022+
white-space: nowrap;
3023+
}
3024+
3025+
.badge-copy-btn:hover {
3026+
background-color: var(--accent-hover);
3027+
transform: translateY(-1px);
3028+
}
3029+
3030+
.badge-copy-btn.copied {
3031+
background-color: #28a745;
3032+
}
3033+
3034+
.badge-copy-btn .copy-icon {
3035+
font-size: 1rem;
3036+
}
3037+
3038+
/* Copy notification */
3039+
.copy-notification {
3040+
background-color: var(--accent-primary);
3041+
color: var(--bg-primary);
3042+
padding: var(--spacing-xs) var(--spacing-md);
3043+
border-radius: var(--radius-sm);
3044+
font-size: 0.875rem;
3045+
font-weight: 600;
3046+
z-index: 3000;
3047+
opacity: 0;
3048+
transform: translateY(10px);
3049+
transition: all 0.3s ease;
3050+
pointer-events: none;
3051+
}
3052+
3053+
.copy-notification.show {
3054+
opacity: 1;
3055+
transform: translateY(0);
3056+
}
3057+
3058+
/* Mobile adjustments for badge modal */
3059+
@media (max-width: 768px) {
3060+
.badge-modal .modal-content {
3061+
margin: 10vh var(--spacing-sm);
3062+
max-height: 80vh;
3063+
}
3064+
3065+
.badge-code-row {
3066+
flex-direction: column;
3067+
}
3068+
3069+
.badge-copy-btn {
3070+
justify-content: center;
3071+
}
3072+
3073+
.badge-format-header {
3074+
flex-direction: column;
3075+
align-items: flex-start;
3076+
gap: var(--spacing-xs);
3077+
}
3078+
}

web/client/js/grid.js

Lines changed: 94 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -603,27 +603,111 @@ function createLangBadge(lang) {
603603
function createBadgeMarkdown(repo) {
604604
if (!repo.id || !repo.place) return '-';
605605

606-
// New format: direct SVG badge (recommended)
606+
return `<button class="badge-btn" onclick="event.stopPropagation(); openBadgeModal(${repo.id});" title="Получить разметку значка">📋 Значок</button>`;
607+
}
608+
609+
// Open badge modal
610+
window.openBadgeModal = function(repoId) {
607611
const apiUrl = window.CONFIG?.dataSource?.apiBaseURL?.replace('/api', '') || 'https://openyellow.openintegrations.dev';
608612
const siteUrl = 'https://openyellow.org';
609-
const markdown = `[![OpenYellow](${apiUrl}/data/badges/${repo.id}.svg)](${siteUrl}/grid?filter=top&repo=${repo.id})`;
610613

611-
return `<input type="text" class="badge-input" value="${markdown.replace(/"/g, '&quot;')}" readonly onclick="event.stopPropagation(); copyBadgeToClipboard(this);" title="Кликните для копирования">`;
612-
}
614+
const svgMarkdown = `[![OpenYellow](${apiUrl}/data/badges/${repoId}.svg)](${siteUrl}/grid?filter=top&repo=${repoId})`;
615+
const pngMarkdown = `[![OpenYellow](${apiUrl}/data/badges/${repoId}.png)](${siteUrl}/grid?filter=top&repo=${repoId})`;
616+
617+
// Create modal if not exists
618+
let badgeModal = document.getElementById('badgeModal');
619+
if (!badgeModal) {
620+
badgeModal = document.createElement('div');
621+
badgeModal.id = 'badgeModal';
622+
badgeModal.className = 'modal badge-modal';
623+
badgeModal.innerHTML = `
624+
<div class="modal-overlay" onclick="closeBadgeModal()"></div>
625+
<div class="modal-content badge-modal-content">
626+
<button class="modal-close" onclick="closeBadgeModal()">×</button>
627+
<h2>Разметка значка</h2>
628+
<p class="badge-modal-description">Выберите формат значка для вставки в README.md</p>
629+
630+
<div class="badge-format-section">
631+
<div class="badge-format-header">
632+
<span class="badge-format-label">SVG (рекомендуется)</span>
633+
<img id="badgePreviewSvg" src="" alt="Badge preview" class="badge-preview-img">
634+
</div>
635+
<div class="badge-code-row">
636+
<input type="text" id="badgeSvgInput" class="badge-modal-input" readonly>
637+
<button class="badge-copy-btn" onclick="copyBadgeMarkdown('svg')">
638+
<span class="copy-icon">📋</span>
639+
<span class="copy-text">Копировать</span>
640+
</button>
641+
</div>
642+
</div>
643+
644+
<div class="badge-format-section">
645+
<div class="badge-format-header">
646+
<span class="badge-format-label">PNG</span>
647+
<img id="badgePreviewPng" src="" alt="Badge preview" class="badge-preview-img">
648+
</div>
649+
<div class="badge-code-row">
650+
<input type="text" id="badgePngInput" class="badge-modal-input" readonly>
651+
<button class="badge-copy-btn" onclick="copyBadgeMarkdown('png')">
652+
<span class="copy-icon">📋</span>
653+
<span class="copy-text">Копировать</span>
654+
</button>
655+
</div>
656+
</div>
657+
</div>
658+
`;
659+
document.body.appendChild(badgeModal);
660+
}
661+
662+
// Update values
663+
document.getElementById('badgeSvgInput').value = svgMarkdown;
664+
document.getElementById('badgePngInput').value = pngMarkdown;
665+
document.getElementById('badgePreviewSvg').src = `${apiUrl}/data/badges/${repoId}.svg`;
666+
document.getElementById('badgePreviewPng').src = `${apiUrl}/data/badges/${repoId}.png`;
667+
668+
// Show modal
669+
badgeModal.classList.add('active');
670+
document.body.style.overflow = 'hidden';
671+
};
672+
673+
// Close badge modal
674+
window.closeBadgeModal = function() {
675+
const badgeModal = document.getElementById('badgeModal');
676+
if (badgeModal) {
677+
badgeModal.classList.remove('active');
678+
document.body.style.overflow = '';
679+
}
680+
};
613681

614-
// Copy badge to clipboard
615-
window.copyBadgeToClipboard = async function(input) {
682+
// Copy badge markdown to clipboard
683+
window.copyBadgeMarkdown = async function(format) {
684+
const inputId = format === 'svg' ? 'badgeSvgInput' : 'badgePngInput';
685+
const input = document.getElementById(inputId);
686+
616687
try {
617688
await navigator.clipboard.writeText(input.value);
618-
showCopyNotification(input);
689+
showBadgeCopyNotification(format);
619690
} catch (err) {
620-
// Fallback for older browsers
621691
input.select();
622692
document.execCommand('copy');
623-
showCopyNotification(input);
693+
showBadgeCopyNotification(format);
624694
}
625695
};
626696

697+
// Show copy notification for badge modal
698+
function showBadgeCopyNotification(format) {
699+
const btn = document.querySelector(`.badge-format-section:nth-child(${format === 'svg' ? 2 : 3}) .badge-copy-btn`);
700+
if (btn) {
701+
const originalText = btn.querySelector('.copy-text').textContent;
702+
btn.querySelector('.copy-text').textContent = 'Скопировано!';
703+
btn.classList.add('copied');
704+
setTimeout(() => {
705+
btn.querySelector('.copy-text').textContent = originalText;
706+
btn.classList.remove('copied');
707+
}, 2000);
708+
}
709+
}
710+
627711
// Show copy notification
628712
function showCopyNotification(element) {
629713
// Create notification
@@ -1123,5 +1207,6 @@ function closeModal() {
11231207
document.addEventListener('keydown', (e) => {
11241208
if (e.key === 'Escape') {
11251209
closeModal();
1210+
closeBadgeModal();
11261211
}
11271212
});

0 commit comments

Comments
 (0)