Compare commits
2 Commits
0d3a514456
...
aa4a4b3e27
| Author | SHA1 | Date | |
|---|---|---|---|
| aa4a4b3e27 | |||
| b776ebbd26 |
@@ -15,7 +15,7 @@ use Filament\Schemas\Components\Utilities\Set;
|
|||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Filament\Schemas\Components\Tabs;
|
use Filament\Schemas\Components\Tabs;
|
||||||
use Filament\Schemas\Components\Tabs\Tab;
|
use Filament\Schemas\Components\Tabs\Tab;
|
||||||
use Filament\Schemas\Components\View;
|
use Filament\Schemas\Components\Livewire;
|
||||||
|
|
||||||
class CareerApplicationForm
|
class CareerApplicationForm
|
||||||
{
|
{
|
||||||
@@ -139,8 +139,8 @@ class CareerApplicationForm
|
|||||||
->nullable()
|
->nullable()
|
||||||
->live(),
|
->live(),
|
||||||
|
|
||||||
// View::make('filament.components.intern-journal-timeline')
|
Livewire::make(\App\Livewire\InternJournalTimeline::class)
|
||||||
// ->columnSpanFull()
|
->columnSpanFull()
|
||||||
])
|
])
|
||||||
])->columnSpanFull()
|
])->columnSpanFull()
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class InternJournalTimeline extends Component
|
||||||
|
{
|
||||||
|
public ?Model $record = null;
|
||||||
|
|
||||||
|
public function getGithubRepoProperty(): ?string
|
||||||
|
{
|
||||||
|
return $this->record?->github_repo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.intern-journal-timeline');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,86 +1,50 @@
|
|||||||
@php
|
@php
|
||||||
$githubRepo = $get('github_repo') ?? ($record ? $record->github_repo : null);
|
$githubRepo = $get('github_repo') ?? ($getRecord ? $getRecord()->github_repo : null);
|
||||||
$uid = 'journal_' . uniqid();
|
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<div id="{{ $uid }}" class="mt-4">
|
<div
|
||||||
<!-- Loader -->
|
x-data="{
|
||||||
<div id="{{ $uid }}-loader" class="hidden py-8 flex flex-col items-center justify-center">
|
githubRepoUrl: @js($githubRepo),
|
||||||
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-primary-600 mb-2"></div>
|
commitDays: [],
|
||||||
<span class="text-xs text-gray-500 font-semibold">GitHub'dan commitler yükleniyor...</span>
|
activeDayIndex: 0,
|
||||||
</div>
|
loading: false,
|
||||||
|
errorMsg: '',
|
||||||
|
isEmpty: false,
|
||||||
|
|
||||||
<!-- Error Alert -->
|
init() {
|
||||||
<div id="{{ $uid }}-error" class="hidden p-4 rounded-xl bg-danger-50 border border-danger-200 text-danger-600 text-xs font-semibold">
|
this.loadCommits();
|
||||||
</div>
|
},
|
||||||
|
|
||||||
<!-- Empty State -->
|
escapeHtml(text) {
|
||||||
<div id="{{ $uid }}-empty" class="hidden p-6 rounded-2xl border border-gray-150 text-center text-gray-400 italic text-sm">
|
if (!text) return '';
|
||||||
Henüz hiç commit bulunamadı veya stajyerin deponuz tanımlanmadı.
|
const div = document.createElement('div');
|
||||||
</div>
|
div.appendChild(document.createTextNode(text));
|
||||||
|
return div.innerHTML;
|
||||||
|
},
|
||||||
|
|
||||||
<!-- Day Paginator / Navbar -->
|
loadCommits() {
|
||||||
<div id="{{ $uid }}-carousel-nav" class="hidden flex items-center justify-between gap-4 p-3 bg-gray-50 border border-gray-100 rounded-2xl mb-6 select-none">
|
if (!this.githubRepoUrl) {
|
||||||
<button type="button" id="{{ $uid }}-prev-day-btn" onclick="{{ $uid }}_navigateDay(-1)" class="w-10 h-10 rounded-xl bg-white hover:bg-gray-100 text-gray-600 border border-gray-200 flex items-center justify-center transition-all shadow-sm">
|
this.isEmpty = true;
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor" class="w-5 h-5">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="flex-grow overflow-x-auto no-scrollbar py-1">
|
|
||||||
<div id="{{ $uid }}-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="{{ $uid }}-next-day-btn" onclick="{{ $uid }}_navigateDay(1)" class="w-10 h-10 rounded-xl bg-white hover:bg-gray-100 text-gray-600 border border-gray-200 flex items-center justify-center transition-all shadow-sm">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor" class="w-5 h-5">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Run on init script -->
|
|
||||||
<script>
|
|
||||||
(function() {
|
|
||||||
const uid = '{{ $uid }}';
|
|
||||||
const githubRepoUrl = @json($githubRepo);
|
|
||||||
let commitDays = [];
|
|
||||||
let activeDayIndex = 0;
|
|
||||||
|
|
||||||
window[uid + '_loadGithubCommits'] = function() {
|
|
||||||
const loader = document.getElementById(uid + '-loader');
|
|
||||||
const errorEl = document.getElementById(uid + '-error');
|
|
||||||
const emptyEl = document.getElementById(uid + '-empty');
|
|
||||||
const navEl = document.getElementById(uid + '-carousel-nav');
|
|
||||||
const containerEl = document.getElementById(uid + '-timeline-container');
|
|
||||||
|
|
||||||
if (!githubRepoUrl) {
|
|
||||||
emptyEl.classList.remove('hidden');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loader.classList.remove('hidden');
|
this.loading = true;
|
||||||
errorEl.classList.add('hidden');
|
this.errorMsg = '';
|
||||||
emptyEl.classList.add('hidden');
|
this.isEmpty = false;
|
||||||
navEl.classList.add('hidden');
|
this.commitDays = [];
|
||||||
containerEl.classList.add('hidden');
|
|
||||||
commitDays = [];
|
|
||||||
|
|
||||||
// Parse owner and repo
|
let repoClean = this.githubRepoUrl.replace(/https?:\/\/(www\.)?github\.com\//i, '');
|
||||||
let repoClean = githubRepoUrl.replace(/https?:\/\/(www\.)?github\.com\//i, '');
|
|
||||||
repoClean = repoClean.replace(/\/$/, '');
|
repoClean = repoClean.replace(/\/$/, '');
|
||||||
const parts = repoClean.split('/');
|
const parts = repoClean.split('/');
|
||||||
if (parts.length < 2) {
|
if (parts.length < 2) {
|
||||||
loader.classList.add('hidden');
|
this.loading = false;
|
||||||
errorEl.textContent = 'Github depo URL\'si çözümlenemedi. Geçerli format: https://github.com/kullanici/depo';
|
this.errorMsg = 'Github depo URL\'si çözümlenemedi. Geçerli format: https://github.com/kullanici/depo';
|
||||||
errorEl.classList.remove('hidden');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const owner = parts[0];
|
const owner = parts[0];
|
||||||
const repo = parts[1].replace(/\.git$/i, '');
|
const repo = parts[1].replace(/\.git$/i, '');
|
||||||
|
|
||||||
fetch(`https://api.github.com/repos/${owner}/${repo}/commits?per_page=100`)
|
fetch('https://api.github.com/repos/' + owner + '/' + repo + '/commits?per_page=100')
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
if (response.status === 404) {
|
if (response.status === 404) {
|
||||||
@@ -94,16 +58,14 @@
|
|||||||
return response.json();
|
return response.json();
|
||||||
})
|
})
|
||||||
.then(commits => {
|
.then(commits => {
|
||||||
loader.classList.add('hidden');
|
this.loading = false;
|
||||||
if (!Array.isArray(commits) || commits.length === 0) {
|
if (!Array.isArray(commits) || commits.length === 0) {
|
||||||
emptyEl.classList.remove('hidden');
|
this.isEmpty = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse to show in chronological order
|
|
||||||
commits.reverse();
|
commits.reverse();
|
||||||
|
|
||||||
// Group commits by date (YYYY-MM-DD)
|
|
||||||
const grouped = {};
|
const grouped = {};
|
||||||
commits.forEach(item => {
|
commits.forEach(item => {
|
||||||
const dateStr = item.commit.author.date;
|
const dateStr = item.commit.author.date;
|
||||||
@@ -118,171 +80,204 @@
|
|||||||
|
|
||||||
const sortedDates = Object.keys(grouped).sort();
|
const sortedDates = Object.keys(grouped).sort();
|
||||||
|
|
||||||
commitDays = sortedDates.map((date, index) => {
|
this.commitDays = sortedDates.map((date, index) => {
|
||||||
const dateParts = date.split('-');
|
const dateParts = date.split('-');
|
||||||
return {
|
return {
|
||||||
date: date,
|
date: date,
|
||||||
dayNum: index + 1,
|
dayNum: index + 1,
|
||||||
formattedDate: `${dateParts[2]}.${dateParts[1]}.${dateParts[0]}`,
|
formattedDate: dateParts[2] + '.' + dateParts[1] + '.' + dateParts[0],
|
||||||
commits: grouped[date]
|
commits: grouped[date].map(c => ({
|
||||||
|
message: c.commit.message,
|
||||||
|
time: new Date(c.commit.author.date).toLocaleTimeString('tr-TR', { hour: '2-digit', minute: '2-digit' }),
|
||||||
|
sha: c.sha.substring(0, 7),
|
||||||
|
url: c.html_url
|
||||||
|
}))
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
if (commitDays.length === 0) {
|
if (this.commitDays.length === 0) {
|
||||||
emptyEl.classList.remove('hidden');
|
this.isEmpty = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
activeDayIndex = 0;
|
this.activeDayIndex = 0;
|
||||||
navEl.classList.remove('hidden');
|
|
||||||
containerEl.classList.remove('hidden');
|
|
||||||
|
|
||||||
renderDayTabs();
|
|
||||||
renderActiveDay();
|
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
loader.classList.add('hidden');
|
this.loading = false;
|
||||||
errorEl.textContent = err.message || 'Bir hata oluştu.';
|
this.errorMsg = err.message || 'Bir hata oluştu.';
|
||||||
errorEl.classList.remove('hidden');
|
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
function renderDayTabs() {
|
get activeDay() {
|
||||||
const container = document.getElementById(uid + '-tabs-container');
|
return this.commitDays[this.activeDayIndex] || null;
|
||||||
container.innerHTML = '';
|
},
|
||||||
|
|
||||||
commitDays.forEach((day, index) => {
|
|
||||||
const isActive = index === activeDayIndex;
|
|
||||||
const activeClass = isActive
|
|
||||||
? 'text-primary-700 bg-primary-50 border border-primary-200 font-extrabold shadow-sm'
|
|
||||||
: 'bg-white hover:bg-gray-50 text-gray-600 border border-gray-200 font-semibold hover:text-primary-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);
|
|
||||||
});
|
|
||||||
|
|
||||||
const activeTab = container.children[activeDayIndex];
|
navigateDay(dir) {
|
||||||
if (activeTab) {
|
const newIndex = this.activeDayIndex + dir;
|
||||||
activeTab.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' });
|
if (newIndex >= 0 && newIndex < this.commitDays.length) {
|
||||||
|
this.activeDayIndex = newIndex;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
const prevBtn = document.getElementById(uid + '-prev-day-btn');
|
selectDay(index) {
|
||||||
const nextBtn = document.getElementById(uid + '-next-day-btn');
|
this.activeDayIndex = index;
|
||||||
|
|
||||||
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() {
|
style="margin-top: 1rem; font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;"
|
||||||
const card = document.getElementById(uid + '-active-day-card');
|
>
|
||||||
|
|
||||||
card.style.opacity = '0.3';
|
|
||||||
card.style.transform = 'translateY(5px)';
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
const day = commitDays[activeDayIndex];
|
|
||||||
|
|
||||||
document.getElementById(uid + '-active-day-title').textContent = `${day.dayNum}. Gün`;
|
|
||||||
document.getElementById(uid + '-active-day-date').innerHTML = `
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-4 h-4 mr-1">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5" />
|
|
||||||
</svg>
|
|
||||||
<span>${day.formattedDate}</span>
|
|
||||||
`;
|
|
||||||
document.getElementById(uid + '-active-day-commit-count').textContent = `${day.commits.length} Commit`;
|
|
||||||
|
|
||||||
const eventsContainer = document.getElementById(uid + '-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-primary-500 flex items-center justify-center transition-all group-hover:bg-primary-500">
|
|
||||||
<div class="w-2 h-2 rounded-full bg-primary-500 group-hover:bg-white transition-all"></div>
|
|
||||||
</div>
|
|
||||||
<!-- Event Card -->
|
|
||||||
<div class="p-4 bg-gray-50/50 hover:bg-primary-50/10 border border-gray-150 hover:border-primary-100 rounded-2xl transition-all shadow-sm">
|
|
||||||
<div class="flex items-center justify-between gap-4 mb-2">
|
|
||||||
<span class="text-xs font-bold text-gray-450 flex items-center gap-1">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-3.5 h-3.5">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
<span>${timeStr}</span>
|
|
||||||
</span>
|
|
||||||
<a href="${commitUrl}" target="_blank" class="text-xs font-mono font-bold text-primary-600 hover:text-primary-700 bg-primary-50 hover:bg-primary-100 px-2.5 py-0.5 rounded-lg border border-primary-100 transition-colors">
|
|
||||||
${shaShort}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<p class="text-sm font-bold text-gray-750 leading-relaxed whitespace-pre-line">${escapeHtml(message)}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
eventsContainer.insertAdjacentHTML('beforeend', eventHtml);
|
|
||||||
});
|
|
||||||
|
|
||||||
card.style.opacity = '1';
|
|
||||||
card.style.transform = 'translateY(0)';
|
|
||||||
}, 150);
|
|
||||||
}
|
|
||||||
|
|
||||||
window[uid + '_navigateDay'] = function(dir) {
|
|
||||||
const newIndex = activeDayIndex + dir;
|
|
||||||
if (newIndex >= 0 && newIndex < commitDays.length) {
|
|
||||||
activeDayIndex = newIndex;
|
|
||||||
renderDayTabs();
|
|
||||||
renderActiveDay();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function escapeHtml(text) {
|
|
||||||
if (!text) return '';
|
|
||||||
return text
|
|
||||||
.replace(/&/g, "&")
|
|
||||||
.replace(/</g, "<")
|
|
||||||
.replace(/>/g, ">")
|
|
||||||
.replace(/"/g, """)
|
|
||||||
.replace(/'/g, "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run on init
|
|
||||||
if (document.readyState === 'loading') {
|
|
||||||
document.addEventListener('DOMContentLoaded', window[uid + '_loadGithubCommits']);
|
|
||||||
} else {
|
|
||||||
window[uid + '_loadGithubCommits']();
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.no-scrollbar::-webkit-scrollbar {
|
.jt-day-btn {
|
||||||
display: none;
|
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
}
|
cursor: pointer;
|
||||||
.no-scrollbar {
|
}
|
||||||
-ms-overflow-style: none;
|
.jt-day-btn:hover {
|
||||||
scrollbar-width: none;
|
transform: translateY(-2px);
|
||||||
}
|
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
|
||||||
|
}
|
||||||
|
.jt-arrow-btn {
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.jt-arrow-btn:hover:not(:disabled) {
|
||||||
|
transform: scale(1.08);
|
||||||
|
background: #eff6ff !important;
|
||||||
|
border-color: #93c5fd !important;
|
||||||
|
}
|
||||||
|
.jt-arrow-btn:disabled {
|
||||||
|
opacity: 0.35;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.jt-event-card {
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
.jt-event-card:hover {
|
||||||
|
transform: translateY(-2px) translateX(3px);
|
||||||
|
box-shadow: 0 12px 24px -8px rgba(59, 130, 246, 0.12);
|
||||||
|
border-color: #bfdbfe !important;
|
||||||
|
background: #ffffff !important;
|
||||||
|
}
|
||||||
|
.jt-timeline-dot {
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
.jt-event-row:hover .jt-timeline-dot {
|
||||||
|
transform: scale(1.2);
|
||||||
|
background-color: #3b82f6 !important;
|
||||||
|
box-shadow: 0 0 0 5px rgba(59, 130, 246, 0.18);
|
||||||
|
}
|
||||||
|
.jt-event-row:hover .jt-timeline-dot-inner {
|
||||||
|
background-color: #ffffff !important;
|
||||||
|
}
|
||||||
|
.jt-sha-link {
|
||||||
|
transition: all 0.25s ease;
|
||||||
|
}
|
||||||
|
.jt-sha-link:hover {
|
||||||
|
background: #3b82f6 !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
border-color: #3b82f6 !important;
|
||||||
|
}
|
||||||
|
.jt-paginator-scroll::-webkit-scrollbar {
|
||||||
|
height: 4px;
|
||||||
|
}
|
||||||
|
.jt-paginator-scroll::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.jt-paginator-scroll::-webkit-scrollbar-thumb {
|
||||||
|
background: #cbd5e1;
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
.jt-paginator-scroll {
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: #cbd5e1 transparent;
|
||||||
|
}
|
||||||
|
@keyframes jt-spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
@keyframes jt-fadeIn {
|
||||||
|
from { opacity: 0; transform: translateY(8px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
.jt-fade-in {
|
||||||
|
animation: jt-fadeIn 0.4s ease-out;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
{{-- Loader --}}
|
||||||
|
<div x-show="loading" x-cloak style="padding: 3rem 0; display: flex; flex-direction: column; align-items: center; justify-content: center;">
|
||||||
|
<div style="width: 2.5rem; height: 2.5rem; border: 2px solid #e2e8f0; border-top-color: #3b82f6; border-radius: 50%; animation: jt-spin 0.8s linear infinite; margin-bottom: 0.75rem;"></div>
|
||||||
|
<span style="font-size: 0.75rem; color: #94a3b8; font-weight: 600; letter-spacing: 0.025em;">Commit geçmişi yükleniyor...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Error --}}
|
||||||
|
<div x-show="errorMsg" x-cloak x-text="errorMsg" style="padding: 1rem 1.25rem; border-radius: 1rem; background: #fef2f2; border: 1px solid #fecaca; color: #dc2626; font-size: 0.75rem; font-weight: 700;"></div>
|
||||||
|
|
||||||
|
{{-- Empty --}}
|
||||||
|
<div x-show="isEmpty && !loading" x-cloak style="padding: 2rem; border-radius: 1.5rem; border: 1px solid #f1f5f9; background: #ffffff; text-align: center; color: #94a3b8; font-style: italic; font-size: 0.875rem;">
|
||||||
|
Henüz hiçbir commit verisi bulunamadı veya depo adresi yapılandırılmadı.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Day Paginator --}}
|
||||||
|
<div x-show="commitDays.length > 0" x-cloak style="display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.75rem; background: rgba(255,255,255,0.8); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid #e2e8f0; border-radius: 1.5rem; margin-bottom: 1.75rem; user-select: none; box-shadow: 0 1px 3px rgba(0,0,0,0.04);">
|
||||||
|
<button type="button" @click="navigateDay(-1)" :disabled="activeDayIndex === 0" class="jt-arrow-btn" style="width: 2.75rem; height: 2.75rem; border-radius: 0.875rem; background: #ffffff; color: #64748b; border: 1px solid #e2e8f0; display: flex; align-items: center; justify-content: center; font-size: 1.25rem; box-shadow: 0 1px 2px rgba(0,0,0,0.04);">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"/></svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="jt-paginator-scroll" style="flex: 1; overflow-x: auto; padding: 0.375rem 0;">
|
||||||
|
<div style="display: flex; gap: 0.625rem; justify-content: center; min-width: max-content; padding: 0 0.5rem;">
|
||||||
|
<template x-for="(day, index) in commitDays" :key="day.date">
|
||||||
|
<button type="button" @click="selectDay(index)" class="jt-day-btn" :style="index === activeDayIndex
|
||||||
|
? 'padding: 0.5rem 1.25rem; border-radius: 0.875rem; display: flex; flex-direction: column; align-items: center; justify-content: center; border: 1.5px solid #93c5fd; background: linear-gradient(135deg, #eff6ff, #dbeafe); color: #1d4ed8; font-weight: 800; box-shadow: 0 2px 8px rgba(59, 130, 246, 0.15);'
|
||||||
|
: 'padding: 0.5rem 1.25rem; border-radius: 0.875rem; display: flex; flex-direction: column; align-items: center; justify-content: center; border: 1px solid #e2e8f0; background: #ffffff; color: #64748b; font-weight: 600;'">
|
||||||
|
<span style="font-size: 0.75rem; line-height: 1.2;" x-text="day.dayNum + '. Gün'"></span>
|
||||||
|
<span style="font-size: 0.6rem; margin-top: 0.125rem; opacity: 0.7; font-weight: 500;" x-text="day.formattedDate"></span>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="button" @click="navigateDay(1)" :disabled="activeDayIndex === commitDays.length - 1" class="jt-arrow-btn" style="width: 2.75rem; height: 2.75rem; border-radius: 0.875rem; background: #ffffff; color: #64748b; border: 1px solid #e2e8f0; display: flex; align-items: center; justify-content: center; font-size: 1.25rem; box-shadow: 0 1px 2px rgba(0,0,0,0.04);">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Active Day Card --}}
|
||||||
|
<div x-show="activeDay" x-cloak class="jt-fade-in" :key="activeDayIndex" style="background: #ffffff; border: 1px solid #f1f5f9; border-radius: 1.5rem; padding: 1.75rem 2rem; box-shadow: 0 4px 20px -4px rgba(15, 23, 42, 0.06);">
|
||||||
|
{{-- Day Header --}}
|
||||||
|
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.75rem; padding-bottom: 1.25rem; border-bottom: 1px solid #f1f5f9;">
|
||||||
|
<div style="display: flex; align-items: center; gap: 0.875rem;">
|
||||||
|
<span style="font-size: 0.875rem; font-weight: 800; color: #2563eb; background: linear-gradient(135deg, #eff6ff, #dbeafe); padding: 0.5rem 1.125rem; border-radius: 1rem; box-shadow: 0 1px 3px rgba(37, 99, 235, 0.1);" x-text="activeDay ? activeDay.dayNum + '. Gün' : ''"></span>
|
||||||
|
<span style="font-size: 0.8125rem; font-weight: 600; color: #94a3b8; display: flex; align-items: center; gap: 0.375rem;">
|
||||||
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="color: #60a5fa;"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
|
||||||
|
<span x-text="activeDay ? activeDay.formattedDate : ''"></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span style="font-size: 0.6875rem; font-weight: 700; color: #94a3b8; background: #f8fafc; border: 1px solid #f1f5f9; padding: 0.375rem 0.875rem; border-radius: 0.625rem;" x-text="activeDay ? activeDay.commits.length + ' Commit' : ''"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Timeline --}}
|
||||||
|
<div style="position: relative; padding-left: 2.25rem;">
|
||||||
|
{{-- Gradient Timeline Line --}}
|
||||||
|
<div style="position: absolute; left: 11px; top: 8px; bottom: 8px; width: 2px; background: linear-gradient(180deg, #3b82f6 0%, #818cf8 40%, #c7d2fe 100%); border-radius: 2px;"></div>
|
||||||
|
|
||||||
|
<div style="display: flex; flex-direction: column; gap: 1.25rem;">
|
||||||
|
<template x-for="(commit, ci) in (activeDay ? activeDay.commits : [])" :key="ci">
|
||||||
|
<div class="jt-event-row" style="position: relative;">
|
||||||
|
{{-- Timeline Dot --}}
|
||||||
|
<div class="jt-timeline-dot" style="position: absolute; left: -32px; top: 6px; width: 24px; height: 24px; border-radius: 50%; background: #ffffff; border: 2.5px solid #3b82f6; display: flex; align-items: center; justify-content: center; z-index: 1;">
|
||||||
|
<div class="jt-timeline-dot-inner" style="width: 8px; height: 8px; border-radius: 50%; background: #3b82f6;"></div>
|
||||||
|
</div>
|
||||||
|
{{-- Event Card --}}
|
||||||
|
<div class="jt-event-card" style="padding: 1.125rem 1.25rem; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 1rem; box-shadow: 0 1px 3px rgba(0,0,0,0.03);">
|
||||||
|
<div style="display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 0.625rem;">
|
||||||
|
<span style="font-size: 0.75rem; font-weight: 700; color: #94a3b8; display: flex; align-items: center; gap: 0.375rem;">
|
||||||
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#60a5fa" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
|
||||||
|
<span x-text="commit.time"></span>
|
||||||
|
</span>
|
||||||
|
<a :href="commit.url" target="_blank" class="jt-sha-link" x-text="commit.sha" style="font-size: 0.6875rem; font-family: 'SF Mono', 'Fira Code', monospace; font-weight: 700; color: #2563eb; background: #eff6ff; padding: 0.25rem 0.75rem; border-radius: 0.5rem; border: 1px solid #bfdbfe; text-decoration: none;"></a>
|
||||||
|
</div>
|
||||||
|
<p style="font-size: 0.8125rem; font-weight: 600; color: #334155; line-height: 1.6; white-space: pre-line; margin: 0;" x-text="commit.message"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,263 @@
|
|||||||
|
<div
|
||||||
|
x-data="{
|
||||||
|
githubRepoUrl: @js($this->githubRepo),
|
||||||
|
commitDays: [],
|
||||||
|
activeDayIndex: 0,
|
||||||
|
loading: false,
|
||||||
|
errorMsg: '',
|
||||||
|
isEmpty: false,
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.loadCommits();
|
||||||
|
},
|
||||||
|
|
||||||
|
loadCommits() {
|
||||||
|
if (!this.githubRepoUrl) {
|
||||||
|
this.isEmpty = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading = true;
|
||||||
|
this.errorMsg = '';
|
||||||
|
this.isEmpty = false;
|
||||||
|
this.commitDays = [];
|
||||||
|
|
||||||
|
let repoClean = this.githubRepoUrl.replace(/https?:\/\/(www\.)?github\.com\//i, '');
|
||||||
|
repoClean = repoClean.replace(/\/$/, '');
|
||||||
|
const parts = repoClean.split('/');
|
||||||
|
if (parts.length < 2) {
|
||||||
|
this.loading = false;
|
||||||
|
this.errorMsg = 'Github depo URL\'si çözümlenemedi. Geçerli format: https://github.com/kullanici/depo';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const owner = parts[0];
|
||||||
|
const repo = parts[1].replace(/\.git$/i, '');
|
||||||
|
|
||||||
|
fetch('https://api.github.com/repos/' + owner + '/' + repo + '/commits?per_page=100')
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
if (response.status === 404) throw new Error('Depo bulunamadı veya private (gizli). Deponuzun public (herkese açık) olduğundan emin olun.');
|
||||||
|
else if (response.status === 403) throw new Error('GitHub API istek limiti aşıldı. Lütfen daha sonra tekrar deneyin.');
|
||||||
|
else throw new Error('GitHub API hatası: ' + response.statusText);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(commits => {
|
||||||
|
this.loading = false;
|
||||||
|
if (!Array.isArray(commits) || commits.length === 0) {
|
||||||
|
this.isEmpty = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
commits.reverse();
|
||||||
|
|
||||||
|
const grouped = {};
|
||||||
|
commits.forEach(item => {
|
||||||
|
const dateStr = item.commit.author.date;
|
||||||
|
if (dateStr) {
|
||||||
|
const dateOnly = dateStr.substring(0, 10);
|
||||||
|
if (!grouped[dateOnly]) grouped[dateOnly] = [];
|
||||||
|
grouped[dateOnly].push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const sortedDates = Object.keys(grouped).sort();
|
||||||
|
|
||||||
|
this.commitDays = sortedDates.map((date, index) => {
|
||||||
|
const dp = date.split('-');
|
||||||
|
return {
|
||||||
|
date: date,
|
||||||
|
dayNum: index + 1,
|
||||||
|
formattedDate: dp[2] + '.' + dp[1] + '.' + dp[0],
|
||||||
|
commits: grouped[date].map(c => ({
|
||||||
|
message: c.commit.message,
|
||||||
|
time: new Date(c.commit.author.date).toLocaleTimeString('tr-TR', { hour: '2-digit', minute: '2-digit' }),
|
||||||
|
sha: c.sha.substring(0, 7),
|
||||||
|
url: c.html_url
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.commitDays.length === 0) {
|
||||||
|
this.isEmpty = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.activeDayIndex = 0;
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.loading = false;
|
||||||
|
this.errorMsg = err.message || 'Bir hata oluştu.';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
get activeDay() {
|
||||||
|
return this.commitDays[this.activeDayIndex] || null;
|
||||||
|
},
|
||||||
|
|
||||||
|
navigateDay(dir) {
|
||||||
|
const n = this.activeDayIndex + dir;
|
||||||
|
if (n >= 0 && n < this.commitDays.length) this.activeDayIndex = n;
|
||||||
|
},
|
||||||
|
|
||||||
|
selectDay(i) {
|
||||||
|
this.activeDayIndex = i;
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
style="margin-top: 1rem; font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;"
|
||||||
|
>
|
||||||
|
<style>
|
||||||
|
.jt-day-btn {
|
||||||
|
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.jt-day-btn:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
|
||||||
|
}
|
||||||
|
.jt-arrow-btn {
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.jt-arrow-btn:hover:not(:disabled) {
|
||||||
|
transform: scale(1.08);
|
||||||
|
background: #eff6ff;
|
||||||
|
border-color: #93c5fd;
|
||||||
|
}
|
||||||
|
.jt-arrow-btn:disabled {
|
||||||
|
opacity: 0.35;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.jt-event-card {
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
.jt-event-card:hover {
|
||||||
|
transform: translateY(-2px) translateX(3px);
|
||||||
|
box-shadow: 0 12px 24px -8px rgba(59, 130, 246, 0.12);
|
||||||
|
border-color: #bfdbfe !important;
|
||||||
|
background: #ffffff !important;
|
||||||
|
}
|
||||||
|
.jt-timeline-dot {
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
.jt-event-row:hover .jt-timeline-dot {
|
||||||
|
transform: scale(1.2);
|
||||||
|
background-color: #3b82f6 !important;
|
||||||
|
box-shadow: 0 0 0 5px rgba(59, 130, 246, 0.18);
|
||||||
|
}
|
||||||
|
.jt-event-row:hover .jt-timeline-dot-inner {
|
||||||
|
background-color: #ffffff !important;
|
||||||
|
}
|
||||||
|
.jt-sha-link {
|
||||||
|
transition: all 0.25s ease;
|
||||||
|
}
|
||||||
|
.jt-sha-link:hover {
|
||||||
|
background: #3b82f6 !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
border-color: #3b82f6 !important;
|
||||||
|
}
|
||||||
|
.jt-paginator-scroll::-webkit-scrollbar {
|
||||||
|
height: 4px;
|
||||||
|
}
|
||||||
|
.jt-paginator-scroll::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.jt-paginator-scroll::-webkit-scrollbar-thumb {
|
||||||
|
background: #cbd5e1;
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
.jt-paginator-scroll {
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: #cbd5e1 transparent;
|
||||||
|
}
|
||||||
|
@keyframes jt-spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
@keyframes jt-fadeIn {
|
||||||
|
from { opacity: 0; transform: translateY(8px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
.jt-fade-in {
|
||||||
|
animation: jt-fadeIn 0.4s ease-out;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
{{-- Loader --}}
|
||||||
|
<div x-show="loading" x-cloak style="padding: 3rem 0; display: flex; flex-direction: column; align-items: center; justify-content: center;">
|
||||||
|
<div style="width: 2.5rem; height: 2.5rem; border: 2px solid #e2e8f0; border-top-color: #3b82f6; border-radius: 50%; animation: jt-spin 0.8s linear infinite; margin-bottom: 0.75rem;"></div>
|
||||||
|
<span style="font-size: 0.75rem; color: #94a3b8; font-weight: 600; letter-spacing: 0.025em;">Commit geçmişi yükleniyor...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Error --}}
|
||||||
|
<div x-show="errorMsg" x-cloak x-text="errorMsg" style="padding: 1rem 1.25rem; border-radius: 1rem; background: #fef2f2; border: 1px solid #fecaca; color: #dc2626; font-size: 0.75rem; font-weight: 700;"></div>
|
||||||
|
|
||||||
|
{{-- Empty --}}
|
||||||
|
<div x-show="isEmpty && !loading" x-cloak style="padding: 2rem; border-radius: 1.5rem; border: 1px solid #f1f5f9; background: #ffffff; text-align: center; color: #94a3b8; font-style: italic; font-size: 0.875rem;">
|
||||||
|
Henüz hiçbir commit verisi bulunamadı veya depo adresi yapılandırılmadı.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Day Paginator --}}
|
||||||
|
<div x-show="commitDays.length > 0" x-cloak style="display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.75rem; background: rgba(255,255,255,0.8); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid #e2e8f0; border-radius: 1.5rem; margin-bottom: 1.75rem; user-select: none; box-shadow: 0 1px 3px rgba(0,0,0,0.04);">
|
||||||
|
<button type="button" @click="navigateDay(-1)" :disabled="activeDayIndex === 0" class="jt-arrow-btn" style="width: 2.75rem; height: 2.75rem; border-radius: 0.875rem; background: #ffffff; color: #64748b; border: 1px solid #e2e8f0; display: flex; align-items: center; justify-content: center; font-size: 1.25rem; box-shadow: 0 1px 2px rgba(0,0,0,0.04);">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"/></svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="jt-paginator-scroll" style="flex: 1; overflow-x: auto; padding: 0.375rem 0;">
|
||||||
|
<div style="display: flex; gap: 0.625rem; justify-content: center; min-width: max-content; padding: 0 0.5rem;">
|
||||||
|
<template x-for="(day, index) in commitDays" :key="day.date">
|
||||||
|
<button type="button" @click="selectDay(index)" class="jt-day-btn" :style="index === activeDayIndex
|
||||||
|
? 'padding: 0.5rem 1.25rem; border-radius: 0.875rem; display: flex; flex-direction: column; align-items: center; justify-content: center; border: 1.5px solid #93c5fd; background: linear-gradient(135deg, #eff6ff, #dbeafe); color: #1d4ed8; font-weight: 800; box-shadow: 0 2px 8px rgba(59, 130, 246, 0.15);'
|
||||||
|
: 'padding: 0.5rem 1.25rem; border-radius: 0.875rem; display: flex; flex-direction: column; align-items: center; justify-content: center; border: 1px solid #e2e8f0; background: #ffffff; color: #64748b; font-weight: 600;'">
|
||||||
|
<span style="font-size: 0.75rem; line-height: 1.2;" x-text="day.dayNum + '. Gün'"></span>
|
||||||
|
<span style="font-size: 0.6rem; margin-top: 0.125rem; opacity: 0.7; font-weight: 500;" x-text="day.formattedDate"></span>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="button" @click="navigateDay(1)" :disabled="activeDayIndex === commitDays.length - 1" class="jt-arrow-btn" style="width: 2.75rem; height: 2.75rem; border-radius: 0.875rem; background: #ffffff; color: #64748b; border: 1px solid #e2e8f0; display: flex; align-items: center; justify-content: center; font-size: 1.25rem; box-shadow: 0 1px 2px rgba(0,0,0,0.04);">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Active Day Card --}}
|
||||||
|
<div x-show="activeDay" x-cloak class="jt-fade-in" :key="activeDayIndex" style="background: #ffffff; border: 1px solid #f1f5f9; border-radius: 1.5rem; padding: 1.75rem 2rem; box-shadow: 0 4px 20px -4px rgba(15, 23, 42, 0.06);">
|
||||||
|
{{-- Day Header --}}
|
||||||
|
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.75rem; padding-bottom: 1.25rem; border-bottom: 1px solid #f1f5f9;">
|
||||||
|
<div style="display: flex; align-items: center; gap: 0.875rem;">
|
||||||
|
<span style="font-size: 0.875rem; font-weight: 800; color: #2563eb; background: linear-gradient(135deg, #eff6ff, #dbeafe); padding: 0.5rem 1.125rem; border-radius: 1rem; box-shadow: 0 1px 3px rgba(37, 99, 235, 0.1);" x-text="activeDay ? activeDay.dayNum + '. Gün' : ''"></span>
|
||||||
|
<span style="font-size: 0.8125rem; font-weight: 600; color: #94a3b8; display: flex; align-items: center; gap: 0.375rem;">
|
||||||
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="color: #60a5fa;"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
|
||||||
|
<span x-text="activeDay ? activeDay.formattedDate : ''"></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span style="font-size: 0.6875rem; font-weight: 700; color: #94a3b8; background: #f8fafc; border: 1px solid #f1f5f9; padding: 0.375rem 0.875rem; border-radius: 0.625rem;" x-text="activeDay ? activeDay.commits.length + ' Commit' : ''"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Timeline --}}
|
||||||
|
<div style="position: relative; padding-left: 2.25rem;">
|
||||||
|
{{-- Gradient Timeline Line --}}
|
||||||
|
<div style="position: absolute; left: 11px; top: 8px; bottom: 8px; width: 2px; background: linear-gradient(180deg, #3b82f6 0%, #818cf8 40%, #c7d2fe 100%); border-radius: 2px;"></div>
|
||||||
|
|
||||||
|
<div style="display: flex; flex-direction: column; gap: 1.25rem;">
|
||||||
|
<template x-for="(commit, ci) in (activeDay ? activeDay.commits : [])" :key="ci">
|
||||||
|
<div class="jt-event-row" style="position: relative;">
|
||||||
|
{{-- Timeline Dot --}}
|
||||||
|
<div class="jt-timeline-dot" style="position: absolute; left: -32px; top: 6px; width: 24px; height: 24px; border-radius: 50%; background: #ffffff; border: 2.5px solid #3b82f6; display: flex; align-items: center; justify-content: center; z-index: 1;">
|
||||||
|
<div class="jt-timeline-dot-inner" style="width: 8px; height: 8px; border-radius: 50%; background: #3b82f6;"></div>
|
||||||
|
</div>
|
||||||
|
{{-- Event Card --}}
|
||||||
|
<div class="jt-event-card" style="padding: 1.125rem 1.25rem; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 1rem; box-shadow: 0 1px 3px rgba(0,0,0,0.03);">
|
||||||
|
<div style="display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 0.625rem;">
|
||||||
|
<span style="font-size: 0.75rem; font-weight: 700; color: #94a3b8; display: flex; align-items: center; gap: 0.375rem;">
|
||||||
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#60a5fa" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
|
||||||
|
<span x-text="commit.time"></span>
|
||||||
|
</span>
|
||||||
|
<a :href="commit.url" target="_blank" class="jt-sha-link" x-text="commit.sha" style="font-size: 0.6875rem; font-family: 'SF Mono', 'Fira Code', monospace; font-weight: 700; color: #2563eb; background: #eff6ff; padding: 0.25rem 0.75rem; border-radius: 0.5rem; border: 1px solid #bfdbfe; text-decoration: none;"></a>
|
||||||
|
</div>
|
||||||
|
<p style="font-size: 0.8125rem; font-weight: 600; color: #334155; line-height: 1.6; white-space: pre-line; margin: 0;" x-text="commit.message"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Reference in New Issue
Block a user