@@ -116,12 +116,14 @@ function processLanguagePosts(langConfig) {
116116 if ( ! ALLOWED_EXTENSIONS . markdown . includes ( ext ) ) return ;
117117
118118 const rawContent = fs . readFileSync ( path . join ( monthPath , file ) , 'utf8' ) ;
119- const content = mdToHtml ( removeMetaTags ( rawContent ) ) ;
119+ const cleanContent = removeMetaTags ( rawContent ) ;
120+ const content = mdToHtml ( cleanContent ) ;
120121 const date = getPostDate ( file , year , monthNum ) ;
121122
122123 posts . push ( {
123124 title : file . match ( / ^ \d { 4 } - \d { 2 } - \d { 2 } - \d { 2 } - \d { 2 } / ) ? formatPostTitle ( file ) : file . replace ( '.md' , '' ) ,
124125 content,
126+ rawContent : cleanContent ,
125127 date,
126128 month : monthNum
127129 } ) ;
@@ -241,10 +243,16 @@ function createCommentsLink(post, language, path) {
241243let createPageWithMenu ;
242244
243245function createPostPage ( post , language ) {
246+ // Создаем копию поста с обработанным контентом для одиночной страницы
247+ const singlePost = {
248+ ...post ,
249+ content : mdToHtml ( removeMetaTags ( post . rawContent || '' ) , true ) // Передаем true для isSinglePost
250+ } ;
251+
244252 return createPageWithMenu (
245253 post . title ,
246254 `<div class="post" data-title="${ post . title . date } " data-time="${ post . title . time } ">
247- ${ post . content }
255+ ${ singlePost . content }
248256 ${ createCommentsSection ( post , language ) }
249257 </div>` ,
250258 language === 'uk' ?'ukr' :'index' ,
@@ -255,13 +263,20 @@ function createPostPage(post, language) {
255263function createFilterInput ( language ) {
256264 const lang = language === 'uk' ? 'uk' : 'en' ;
257265 const placeholder = lang === 'uk' ? 'Фільтр:' : 'Filter:' ;
266+ const githubBtnText = lang === 'uk' ? 'У всіх постах (GitHub)' : 'In all posts (GitHub)' ;
258267
259268 return `
260269 <div class="filter-wrapper">
261270 <div class="input-container">
262271 <input type="text" id="postsFilter" class="posts-filter" placeholder="${ placeholder } " autocomplete="off">
263272 <button type="button" id="clearFilter" class="clear-filter" aria-label="Очистить">✕</button>
264273 </div>
274+ <button type="button" id="githubSearchBtn" class="github-search-btn" aria-label="Search in GitHub">
275+ <svg viewBox="0 0 16 16">
276+ <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>
277+ </svg>
278+ ${ githubBtnText }
279+ </button>
265280 <div id="tagSuggestionsWrapper" class="tags-suggestions">
266281 <div id="tagSuggestions" class="tag-chips"></div>
267282 </div>
@@ -270,11 +285,79 @@ function createFilterInput(language) {
270285 document.addEventListener('DOMContentLoaded', () => {
271286 const filterInput = document.getElementById('postsFilter');
272287 const clearFilterBtn = document.getElementById('clearFilter');
288+ const githubSearchBtn = document.getElementById('githubSearchBtn');
273289 const posts = document.querySelectorAll('.post-wrapper');
274290 const tagSuggestions = document.getElementById('tagSuggestions');
275291 const tagSuggestionsWrapper = document.getElementById('tagSuggestionsWrapper');
276292 const minChars = 3;
277293
294+ // Управление расширением поля фильтра
295+ filterInput.addEventListener('focus', () => {
296+ filterInput.classList.add('expanded');
297+ // Показываем кнопку GitHub поиска при фокусе, если есть текст
298+ if (filterInput.value.trim().length > 0) {
299+ githubSearchBtn.classList.add('visible');
300+ }
301+ // Показываем кнопку очистки, если есть текст
302+ toggleClearButton();
303+ });
304+
305+ // Обновленная логика сворачивания поля
306+ filterInput.addEventListener('blur', () => {
307+ // Сужаем поле только если оно пустое
308+ if (filterInput.value.trim() === '') {
309+ filterInput.classList.remove('expanded');
310+ githubSearchBtn.classList.remove('visible');
311+ } else {
312+ // Если есть текст, оставляем поле развернутым
313+ filterInput.classList.add('expanded');
314+ }
315+ });
316+
317+ // Обработчик для кнопки поиска в GitHub
318+ githubSearchBtn.addEventListener('click', () => {
319+ const searchText = filterInput.value.trim();
320+ if (searchText.length > 0) {
321+ const encodedQuery = encodeURIComponent("repo:danvoronov/CodeWithLLM-Updates " + searchText);
322+ window.open("https://github.com/search?q=" + encodedQuery + " language%3AMarkdown&type=code", '_blank');
323+ }
324+ });
325+
326+ // Обновляем состояние поля и кнопок при вводе
327+ filterInput.addEventListener('input', () => {
328+ const hasText = filterInput.value.trim().length > 0;
329+
330+ // Управляем видимостью кнопки GitHub и состоянием поля
331+ if (hasText) {
332+ githubSearchBtn.classList.add('visible');
333+ filterInput.classList.add('expanded');
334+ } else {
335+ githubSearchBtn.classList.remove('visible');
336+ }
337+
338+ // Обновляем поиск и кнопку очистки
339+ updateSearch();
340+ toggleClearButton();
341+ });
342+
343+ // Добавляем обработчик клика по дате в вертикальной полоске
344+ document.querySelectorAll('.post').forEach(post => {
345+ // Используем делегирование событий для ::after
346+ post.addEventListener('click', (e) => {
347+ // Проверяем, был ли клик по ::after элементу
348+ // Для этого проверяем координаты клика относительно поста
349+ const rect = post.getBoundingClientRect();
350+ const isClickOnAfter = e.clientX <= rect.left + 30; // 30px - примерная ширина ::after
351+
352+ if (isClickOnAfter) {
353+ const postUrl = post.getAttribute('data-post-url');
354+ if (postUrl) {
355+ window.location.href = postUrl;
356+ }
357+ }
358+ });
359+ });
360+
278361 // Запоминаем положение скролла перед фильтрацией
279362 let lastScrollPosition = 0;
280363 let lastHighlightedPosts = [];
@@ -296,13 +379,18 @@ function createFilterInput(language) {
296379 clearFilterBtn.addEventListener('click', () => {
297380 filterInput.value = '';
298381 updateSearch();
299- filterInput.focus();
382+ filterInput.focus(); // Сохраняем фокус на поле
300383 toggleClearButton();
384+ githubSearchBtn.classList.remove('visible'); // Скрываем кнопку GitHub
385+
386+ // Не сужаем поле, так как оно в фокусе
301387 });
302388
303389 // Функция для отображения/скрытия кнопки очистки
304390 function toggleClearButton() {
305- clearFilterBtn.style.display = filterInput.value.length > 0 ? 'block' : 'none';
391+ // Всегда показываем кнопку очистки, если в поле есть текст
392+ const hasText = filterInput.value.trim().length > 0;
393+ clearFilterBtn.style.display = hasText ? 'block' : 'none';
306394 }
307395
308396 // Инициализация состояния кнопки очистки
@@ -480,12 +568,22 @@ function createFilterInput(language) {
480568
481569 // Очистка фильтра при нажатии Escape
482570 document.addEventListener('keydown', function(e) {
483- if (e.key === 'Escape' && document.activeElement === filterInput) {
484- filterInput.value = '';
485- updateSearch();
486- filterInput.blur();
487- tagSuggestionsWrapper.classList.remove('visible');
488- toggleClearButton();
571+ if (e.key === 'Escape') {
572+ // Проверяем, есть ли текст в поле фильтра
573+ if (filterInput.value.trim() !== '') {
574+ filterInput.classList.remove('expanded');
575+ filterInput.value = '';
576+ updateSearch();
577+ toggleClearButton();
578+ githubSearchBtn.classList.remove('visible'); // Скрываем кнопку GitHub
579+ tagSuggestionsWrapper.classList.remove('visible');
580+
581+ // Если фокус был в поле ввода, убираем его
582+ if (document.activeElement === filterInput) {
583+ filterInput.blur();
584+ // Поле сузится автоматически в обработчике blur, так как оно пустое
585+ }
586+ }
489587 }
490588 });
491589 });
@@ -508,7 +606,7 @@ function createMonthArchivePage(posts, month, year, language, monthsData, curren
508606 const fullPath = `${ basePath } ${ monthKey } /${ postSlug } /` ;
509607 return `
510608 <div class="post-wrapper">
511- <div class="post" data-title="${ post . title . date } " data-time="${ post . title . time } " data-date="${ post . date } ">
609+ <div class="post" data-title="${ post . title . date } " data-time="${ post . title . time } " data-date="${ post . date } " data-post-url=" ${ fullPath } " >
512610 ${ post . content }
513611 ${ createCommentsLink ( post , language , fullPath ) }
514612 </div>
@@ -624,14 +722,15 @@ function createBlogContent(posts, language) {
624722 const postSlug = getPostSlug ( post ) ;
625723 const date = new Date ( post . date ) ;
626724 const monthKey = `${ date . getFullYear ( ) } -${ String ( date . getMonth ( ) + 1 ) . padStart ( 2 , '0' ) } ` ;
627- const path = language === 'uk' ?
628- `${ siteUrl } ua/${ monthKey } /${ postSlug } /` :
629- `${ siteUrl } ${ monthKey } /${ postSlug } /` ;
725+ const relativePath = language === 'uk' ?
726+ `/ua/${ monthKey } /${ postSlug } /` :
727+ `/${ monthKey } /${ postSlug } /` ;
728+ const fullPath = `${ siteUrl } ${ relativePath . substring ( 1 ) } ` ;
630729 return `
631730 <div class="post-wrapper">
632- <div class="post" data-title="${ post . title . date } " data-time="${ post . title . time } " data-date="${ post . date } ">
731+ <div class="post" data-title="${ post . title . date } " data-time="${ post . title . time } " data-date="${ post . date } " data-post-url=" ${ fullPath } " >
633732 ${ post . content }
634- ${ createCommentsLink ( post , language , path ) }
733+ ${ createCommentsLink ( post , language , relativePath ) }
635734 </div>
636735 </div>
637736 ` ;
@@ -756,16 +855,6 @@ function generateMenu(activeMenu, posts = [], currentMonth = '') {
756855 body.classList.toggle('menu-open');
757856 });
758857 });
759-
760- document.addEventListener('keydown', function(e) {
761- if (e.key === 'Escape') {
762- const filterInput = document.getElementById('postsFilter');
763- if (filterInput) {
764- filterInput.value = '';
765- filterInput.dispatchEvent(new Event('input'));
766- }
767- }
768- });
769858 </script>` ;
770859}
771860
@@ -820,7 +909,7 @@ function createPage(title, content, activeMenu, posts = [], currentMonth = '', p
820909 <body>
821910 <div class="wrapper">
822911 ${ preGeneratedMenu || generateMenu ( activeMenu , posts , currentMonth ) }
823- ${ ( activeMenu === 'index' || activeMenu === 'ukr' ) ? createFilterInput ( activeMenu === 'ukr' ? 'uk' : 'en' ) : '' }
912+ ${ ( activeMenu === 'index' || activeMenu === 'ukr' ) && posts . length > 1 ? createFilterInput ( activeMenu === 'ukr' ? 'uk' : 'en' ) : '' }
824913 ${ content }
825914 </div>
826915 </body>
0 commit comments