184 lines
12 KiB
PHP
184 lines
12 KiB
PHP
@extends('layouts.app')
|
|
|
|
@section('title', 'Claude Code 뉴스')
|
|
|
|
@push('styles')
|
|
<style>
|
|
/* Markdown 렌더링 스타일 */
|
|
.release-body h1 { font-size: 1.25rem; font-weight: 700; margin: 1rem 0 0.5rem; color: #1f2937; }
|
|
.release-body h2 { font-size: 1.125rem; font-weight: 600; margin: 1rem 0 0.5rem; color: #374151; }
|
|
.release-body h3 { font-size: 1rem; font-weight: 600; margin: 0.75rem 0 0.375rem; color: #4b5563; }
|
|
.release-body p { margin: 0.5rem 0; line-height: 1.625; color: #374151; }
|
|
.release-body ul { list-style-type: disc; padding-left: 1.5rem; margin: 0.5rem 0; }
|
|
.release-body ol { list-style-type: decimal; padding-left: 1.5rem; margin: 0.5rem 0; }
|
|
.release-body li { margin: 0.25rem 0; line-height: 1.5; color: #374151; }
|
|
.release-body code { background: #f3f4f6; padding: 0.125rem 0.375rem; border-radius: 0.25rem; font-size: 0.875rem; color: #dc2626; }
|
|
.release-body pre { background: #1f2937; color: #e5e7eb; padding: 1rem; border-radius: 0.5rem; overflow-x: auto; margin: 0.75rem 0; }
|
|
.release-body pre code { background: transparent; color: inherit; padding: 0; }
|
|
.release-body a { color: #2563eb; text-decoration: underline; }
|
|
.release-body a:hover { color: #1d4ed8; }
|
|
.release-body blockquote { border-left: 3px solid #d1d5db; padding-left: 1rem; margin: 0.75rem 0; color: #6b7280; }
|
|
.release-body hr { border: none; border-top: 1px solid #e5e7eb; margin: 1rem 0; }
|
|
.release-body table { border-collapse: collapse; width: 100%; margin: 0.75rem 0; }
|
|
.release-body th, .release-body td { border: 1px solid #d1d5db; padding: 0.5rem 0.75rem; text-align: left; }
|
|
.release-body th { background: #f9fafb; font-weight: 600; }
|
|
</style>
|
|
@endpush
|
|
|
|
@section('content')
|
|
<div class="space-y-6" x-data="{ lang: localStorage.getItem('claude-news-lang') || 'ko' }"
|
|
x-init="$watch('lang', val => localStorage.setItem('claude-news-lang', val))">
|
|
|
|
{{-- 페이지 헤더 --}}
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h1 class="text-2xl font-bold text-gray-900">Claude Code 뉴스</h1>
|
|
<p class="mt-1 text-sm text-gray-500">GitHub Releases에서 최신 업데이트를 확인합니다.</p>
|
|
</div>
|
|
<div class="flex items-center gap-3">
|
|
{{-- 한/영 토글 --}}
|
|
<div class="inline-flex rounded-lg border border-gray-300 overflow-hidden">
|
|
<button @click="lang = 'ko'"
|
|
:class="lang === 'ko' ? 'bg-indigo-600 text-white border-indigo-600' : 'bg-white text-gray-600 hover:bg-gray-50'"
|
|
class="px-3 py-1.5 text-sm font-medium transition-colors">
|
|
한국어
|
|
</button>
|
|
<button @click="lang = 'en'"
|
|
:class="lang === 'en' ? 'bg-indigo-600 text-white border-indigo-600' : 'bg-white text-gray-600 hover:bg-gray-50'"
|
|
class="px-3 py-1.5 text-sm font-medium transition-colors border-l border-gray-300">
|
|
English
|
|
</button>
|
|
</div>
|
|
|
|
<form action="{{ route('claude-code.news.refresh-cache') }}" method="POST">
|
|
@csrf
|
|
<button type="submit" class="inline-flex items-center gap-1.5 px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
|
|
새로고침
|
|
</button>
|
|
</form>
|
|
<a href="https://github.com/anthropics/claude-code/releases" target="_blank" rel="noopener"
|
|
class="inline-flex items-center gap-1.5 px-3 py-2 text-sm font-medium text-white bg-gray-800 rounded-lg hover:bg-gray-700">
|
|
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
|
|
GitHub
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- 성공 메시지 --}}
|
|
@if(session('success'))
|
|
<div class="p-3 text-sm text-green-700 bg-green-50 border border-green-200 rounded-lg">
|
|
{{ session('success') }}
|
|
</div>
|
|
@endif
|
|
|
|
@if(count($releases) > 0)
|
|
{{-- 요약 카드 --}}
|
|
<div class="flex gap-4" style="flex-wrap: wrap;">
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4" style="flex: 1 1 200px; max-width: 300px;">
|
|
<div class="text-sm text-gray-500">최신 버전</div>
|
|
<div class="text-xl font-bold text-indigo-600 mt-1">{{ $releases[0]['tag_name'] }}</div>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4" style="flex: 1 1 200px; max-width: 300px;">
|
|
<div class="text-sm text-gray-500">총 릴리즈</div>
|
|
<div class="text-xl font-bold text-gray-900 mt-1">{{ count($releases) }}건</div>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4" style="flex: 1 1 200px; max-width: 300px;">
|
|
<div class="text-sm text-gray-500">최근 릴리즈</div>
|
|
<div class="text-xl font-bold text-gray-900 mt-1">
|
|
{{ \Carbon\Carbon::parse($releases[0]['published_at'])->format('Y-m-d') }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- 릴리즈 목록 --}}
|
|
<div class="space-y-4">
|
|
@foreach($releases as $index => $release)
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
|
|
{{-- 헤더 --}}
|
|
<div class="flex items-center justify-between px-5 py-3 bg-gray-50 border-b border-gray-200 cursor-pointer"
|
|
onclick="toggleRelease({{ $index }})">
|
|
<div class="flex items-center gap-3">
|
|
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-semibold
|
|
{{ $release['prerelease'] ? 'bg-yellow-100 text-yellow-800' : 'bg-indigo-100 text-indigo-800' }}">
|
|
{{ $release['tag_name'] }}
|
|
</span>
|
|
<span class="text-sm font-medium text-gray-700">{{ $release['name'] }}</span>
|
|
@if($release['prerelease'])
|
|
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-yellow-50 text-yellow-700 border border-yellow-200">
|
|
Pre-release
|
|
</span>
|
|
@endif
|
|
</div>
|
|
<div class="flex items-center gap-3">
|
|
<div class="flex items-center gap-1.5 text-xs text-gray-500">
|
|
@if($release['author_avatar'])
|
|
<img src="{{ $release['author_avatar'] }}" alt="" class="w-4 h-4 rounded-full">
|
|
@endif
|
|
<span>{{ $release['author'] }}</span>
|
|
</div>
|
|
<span class="text-xs text-gray-400">
|
|
{{ \Carbon\Carbon::parse($release['published_at'])->format('Y-m-d H:i') }}
|
|
</span>
|
|
<a href="{{ $release['html_url'] }}" target="_blank" rel="noopener"
|
|
class="text-gray-400 hover:text-gray-600" onclick="event.stopPropagation()">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/></svg>
|
|
</a>
|
|
<svg class="w-4 h-4 text-gray-400 transition-transform" id="chevron-{{ $index }}" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- 본문 (첫번째만 열림) --}}
|
|
<div id="release-body-{{ $index }}" class="{{ $index === 0 ? '' : 'hidden' }}">
|
|
<div class="px-5 py-4 release-body text-sm">
|
|
<div x-show="lang === 'ko'">{!! $release['body_html_ko'] ?? $release['body_html'] !!}</div>
|
|
<div x-show="lang === 'en'">{!! $release['body_html'] !!}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
@else
|
|
{{-- 빈 상태 --}}
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-12 text-center">
|
|
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"/>
|
|
</svg>
|
|
<h3 class="mt-4 text-lg font-medium text-gray-900">릴리즈 정보를 불러올 수 없습니다</h3>
|
|
<p class="mt-2 text-sm text-gray-500">GitHub API에 접속할 수 없거나 릴리즈가 없습니다.</p>
|
|
<div class="mt-4">
|
|
<form action="{{ route('claude-code.news.refresh-cache') }}" method="POST" class="inline">
|
|
@csrf
|
|
<button type="submit" class="inline-flex items-center gap-1.5 px-4 py-2 text-sm font-medium text-white bg-indigo-600 rounded-lg hover:bg-indigo-700">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
|
|
다시 시도
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<script>
|
|
function toggleRelease(index) {
|
|
const body = document.getElementById('release-body-' + index);
|
|
const chevron = document.getElementById('chevron-' + index);
|
|
if (body.classList.contains('hidden')) {
|
|
body.classList.remove('hidden');
|
|
chevron.style.transform = 'rotate(180deg)';
|
|
} else {
|
|
body.classList.add('hidden');
|
|
chevron.style.transform = '';
|
|
}
|
|
}
|
|
|
|
// 첫번째 항목 chevron 초기 상태
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const firstChevron = document.getElementById('chevron-0');
|
|
if (firstChevron) {
|
|
firstChevron.style.transform = 'rotate(180deg)';
|
|
}
|
|
});
|
|
</script>
|
|
@endsection
|