@@ -394,8 +394,42 @@
Henüz hiç commit bulunamadı veya deponuz tanı mlanmadı . Lütfen deponuzu tanı mlayı n ve commitlerinizi gönderin .
</ div >
< div id = " commits-timeline " class = " hidden relative border-l-2 border-slate-100 ml-4 pl-6 space-y-6 " >
<!-- Loaded dynamically by JS -- >
<!-- Day Paginator / Navbar -- >
< div id = " journal-carousel-nav " class = " hidden flex items-center justify-between gap-4 p-3 bg-slate-50/80 border border-slate-100 rounded-2xl mb-6 select-none " >
< button type = " button " id = " prev-day-btn " onclick = " navigateDay(-1) " class = " w-10 h-10 rounded-xl bg-white hover:bg-blue-50 text-slate-600 hover:text-blue-600 border border-slate-200/60 hover:border-blue-100 flex items-center justify-center transition-all shadow-sm " >
< i class = " uil uil-angle-left text-xl " ></ i >
</ button >
< div class = " flex-grow overflow-x-auto no-scrollbar py-1 " >
< div id = " day-tabs-container " class = " flex gap-2 justify-start sm:justify-center min-w-max px-2 " >
<!-- Day tabs rendered dynamically -->
</ div >
</ div >
< button type = " button " id = " next-day-btn " onclick = " navigateDay(1) " class = " w-10 h-10 rounded-xl bg-white hover:bg-blue-50 text-slate-600 hover:text-blue-600 border border-slate-200/60 hover:border-blue-100 flex items-center justify-center transition-all shadow-sm " >
< i class = " uil uil-angle-right text-xl " ></ i >
</ button >
</ div >
<!-- Day Content Timeline Container ( Carousel View ) -->
< div id = " commits-timeline-container " class = " hidden " >
< div id = " active-day-card " class = " bg-white border border-slate-100/80 rounded-2xl p-6 shadow-sm transition-all duration-300 transform " >
<!-- Active Day Details ( Date / Day Title ) -->
< div class = " flex items-center justify-between mb-8 pb-4 border-b border-slate-100 " >
< div class = " flex items-center gap-3 " >
< span id = " active-day-title " class = " text-base font-extrabold text-blue-600 bg-blue-50 px-4 py-1.5 rounded-full " > 1. Gün </ span >
< span id = " active-day-date " class = " text-sm font-semibold text-slate-400 " >< i class = " uil uil-calendar-alt mr-1 " ></ i > 29.05 . 2026 </ span >
</ div >
< span id = " active-day-commit-count " class = " text-xs font-bold text-slate-400 bg-slate-50 border border-slate-100 px-2.5 py-1 rounded-lg " > 3 Commit </ span >
</ div >
<!-- Timeline items list -->
< div class = " relative pl-6 sm:pl-8 before:content-[''] before:absolute before:left-[11px] sm:before:left-[15px] before:top-2 before:bottom-2 before:w-[2px] before:bg-slate-100 " >
< div id = " timeline-events " class = " space-y-6 " >
<!-- Event items rendered dynamically -->
</ div >
</ div >
</ div >
</ div >
</ div >
@@ -459,12 +493,15 @@
});
const githubRepoUrl = @ json ( $intern -> github_repo );
let commitDays = [];
let activeDayIndex = 0 ;
function loadGithubCommits () {
const loader = document . getElementById ( 'commits-loader' );
const errorEl = document . getElementById ( 'commits-error' );
const emptyEl = document . getElementById ( 'commits-empty' );
const timelineEl = document . getElementById ( 'commits-timeline ' );
const navEl = document . getElementById ( 'journal-carousel-nav ' );
const containerEl = document . getElementById ( 'commits-timeline-container' );
if ( ! githubRepoUrl ) {
emptyEl . classList . remove ( 'hidden' );
@@ -474,8 +511,9 @@
loader . classList . remove ( 'hidden' );
errorEl . classList . add ( 'hidden' );
emptyEl . classList . add ( 'hidden' );
timelineEl . classList . add ( 'hidden' );
timelineEl . innerHTML = ' ';
navEl . classList . add ( 'hidden' );
containerEl . classList . add ( 'hidden ') ;
commitDays = [];
// Parse owner and repo
let repoClean = githubRepoUrl . replace ( / https ? : \ / \ / ( www\ . ) ? github\ . com\ //i, '');
@@ -513,42 +551,42 @@
// Reverse to show in chronological order (Day 1, Day 2...)
commits . reverse ();
timelineEl . classList . remove ( 'hidden' );
commits . forEach (( item , index ) => {
const dayNum = index + 1 ;
const message = item . commit . message ;
const authorDate = new Date ( item . commit . author . date );
const formattedDate = authorDate . toLocaleDateString ( 'tr-TR' , {
day : '2-digit' ,
month : '2-digit' ,
year : 'numeric' ,
hour : '2-digit' ,
minute : '2-digit'
});
const shaShort = item . sha . substring ( 0 , 7 );
const commitUrl = item . html_url ;
const commitHtml = `
< div class = " relative pl-6 pb-6 last:pb-0 " >
< div class = " absolute -left-[7px] top-1.5 w-3 h-3 rounded-full bg-blue-600 shadow-sm ring-4 ring-white " ></ div >
< div class = " bg-slate-50/60 rounded-2xl p-4 border border-slate-100 hover:border-slate-200 hover:bg-slate-50 transition-all " >
< div class = " flex flex-wrap items-center justify-between gap-2 mb-2 " >
< span class = " text-xs uppercase font-extrabold tracking-wider text-blue-600 bg-blue-50 px-2.5 py-1 rounded-full " > $ { dayNum } . Gün </ span >
< div class = " flex items-center gap-2 " >
< span class = " text-xs text-slate-400 font-semibold " > $ { formattedDate } </ span >
< a href = " ${ commitUrl } " target = " _blank " class = " text-xs font-mono font-bold text-slate-500 hover:text-blue-600 bg-white px-2 py-0.5 rounded border border-slate-200/60 transition-colors flex items-center gap-1 " >
< i class = " uil uil-external-link-alt text-[10px] " ></ i >
$ { shaShort }
</ a >
</ div >
</ div >
< p class = " text-sm font-bold text-slate-700 whitespace-pre-line leading-relaxed " > $ { escapeHtml ( message )} </ p >
</ div >
</ div >
` ;
timelineEl . insertAdjacentHTML ( 'beforeend' , commitHtml );
// Group commits by date (YYYY-MM-DD)
const grouped = {};
commits . forEach ( item => {
const dateStr = item . commit . author . date ;
if ( dateStr ) {
const dateOnly = dateStr . substring ( 0 , 10 ); // "YYYY-MM-DD"
if ( ! grouped [ dateOnly ]) {
grouped [ dateOnly ] = [];
}
grouped [ dateOnly ] . push ( item );
}
});
const sortedDates = Object . keys ( grouped ) . sort ();
commitDays = sortedDates . map (( date , index ) => {
const dateParts = date . split ( '-' );
return {
date : date ,
dayNum : index + 1 ,
formattedDate : `${dateParts[2]}.${dateParts[1]}.${dateParts[0]}` ,
commits : grouped [ date ]
};
});
if ( commitDays . length === 0 ) {
emptyEl . classList . remove ( 'hidden' );
return ;
}
activeDayIndex = 0 ;
navEl . classList . remove ( 'hidden' );
containerEl . classList . remove ( 'hidden' );
renderDayTabs ();
renderActiveDay ();
})
. catch ( err => {
loader . classList . add ( 'hidden' );
@@ -557,6 +595,109 @@
});
}
function renderDayTabs () {
const container = document . getElementById ( 'day-tabs-container' );
container . innerHTML = '' ;
commitDays . forEach (( day , index ) => {
const isActive = index === activeDayIndex ;
const activeClass = isActive
? 'text-blue-700 bg-blue-50 border border-blue-200 font-extrabold shadow-sm'
: 'bg-white hover:bg-slate-50 text-slate-600 border border-slate-200/60 font-semibold hover:text-blue-600' ;
const tab = document . createElement ( 'button' );
tab . type = 'button' ;
tab . className = `px-5 py-2 rounded-xl transition-all flex flex-col items-center justify-center ${activeClass}` ;
tab . innerHTML = `
< span class = " text-xs " > $ { day . dayNum } . Gün </ span >
< span class = " text-[9px] mt-0.5 opacity-70 font-medium " > $ { day . formattedDate } </ span >
` ;
tab . onclick = () => {
activeDayIndex = index ;
renderDayTabs ();
renderActiveDay ();
};
container . appendChild ( tab );
});
// Handle scroll to active element
const activeTab = container . children [ activeDayIndex ];
if ( activeTab ) {
activeTab . scrollIntoView ({ behavior : 'smooth' , block : 'nearest' , inline : 'center' });
}
// Disable/enable arrows
const prevBtn = document . getElementById ( 'prev-day-btn' );
const nextBtn = document . getElementById ( 'next-day-btn' );
prevBtn . disabled = activeDayIndex === 0 ;
prevBtn . classList . toggle ( 'opacity-40' , activeDayIndex === 0 );
prevBtn . classList . toggle ( 'cursor-not-allowed' , activeDayIndex === 0 );
nextBtn . disabled = activeDayIndex === commitDays . length - 1 ;
nextBtn . classList . toggle ( 'opacity-40' , activeDayIndex === commitDays . length - 1 );
nextBtn . classList . toggle ( 'cursor-not-allowed' , activeDayIndex === commitDays . length - 1 );
}
function renderActiveDay () {
const card = document . getElementById ( 'active-day-card' );
// Smooth transition
card . style . opacity = '0.3' ;
card . style . transform = 'translateY(5px)' ;
setTimeout (() => {
const day = commitDays [ activeDayIndex ];
document . getElementById ( 'active-day-title' ) . textContent = `${day.dayNum}. Gün` ;
document . getElementById ( 'active-day-date' ) . innerHTML = `<i class="uil uil-calendar-alt mr-1"></i> ${day.formattedDate}` ;
document . getElementById ( 'active-day-commit-count' ) . textContent = `${day.commits.length} Commit` ;
const eventsContainer = document . getElementById ( 'timeline-events' );
eventsContainer . innerHTML = '' ;
day . commits . forEach ( c => {
const message = c . commit . message ;
const authorDate = new Date ( c . commit . author . date );
const timeStr = authorDate . toLocaleTimeString ( 'tr-TR' , { hour : '2-digit' , minute : '2-digit' });
const shaShort = c . sha . substring ( 0 , 7 );
const commitUrl = c . html_url ;
const eventHtml = `
< div class = " relative group " >
<!-- Timeline Dot -->
< div class = " absolute -left-[31px] sm:-left-[39px] top-1.5 w-6 h-6 rounded-full bg-white border-2 border-blue-500 flex items-center justify-center transition-all group-hover:bg-blue-500 " >
< div class = " w-2 h-2 rounded-full bg-blue-500 group-hover:bg-white transition-all " ></ div >
</ div >
<!-- Event Card -->
< div class = " p-4 bg-slate-50/50 hover:bg-blue-50/10 border border-slate-100 hover:border-blue-100/60 rounded-2xl transition-all shadow-sm " >
< div class = " flex items-center justify-between gap-4 mb-2 " >
< span class = " text-xs font-bold text-slate-400 " >< i class = " uil uil-clock mr-1 " ></ i > $ { timeStr } </ span >
< a href = " ${ commitUrl } " target = " _blank " class = " text-xs font-mono font-bold text-blue-600 hover:text-blue-700 bg-blue-50/60 hover:bg-blue-50 px-2.5 py-0.5 rounded-lg border border-blue-100/40 transition-colors " >
$ { shaShort }
</ a >
</ div >
< p class = " text-sm font-bold text-slate-700 leading-relaxed whitespace-pre-line " > $ { escapeHtml ( message )} </ p >
</ div >
</ div >
` ;
eventsContainer . insertAdjacentHTML ( 'beforeend' , eventHtml );
});
card . style . opacity = '1' ;
card . style . transform = 'translateY(0)' ;
}, 150 );
}
function navigateDay ( dir ) {
const newIndex = activeDayIndex + dir ;
if ( newIndex >= 0 && newIndex < commitDays . length ) {
activeDayIndex = newIndex ;
renderDayTabs ();
renderActiveDay ();
}
}
function escapeHtml ( text ) {
if ( ! text ) return '' ;
return text
@@ -653,6 +794,13 @@
. tab - btn . active span . text - slate - 800 {
color : #1e40af !important;
}
. no - scrollbar ::- webkit - scrollbar {
display : none ;
}
. no - scrollbar {
- ms - overflow - style : none ;
scrollbar - width : none ;
}
</ style >
@ endpush
@ endsection