feat: redesign music production metadata table with localized labels and styled UI components

This commit is contained in:
Ümit Tunç
2026-06-01 09:16:30 +03:00
parent 31e695cd3a
commit faf752dd3c
4 changed files with 367 additions and 63 deletions
+144
View File
@@ -0,0 +1,144 @@
<?php
return [
// Navigation & list
'nav-music-productions' => 'الإنتاج الموسيقي',
'breadcrumb_home' => 'الرئيسية',
'meta-index-subtitle' => 'Truncgil',
'meta-index-title' => 'إنتاج موسيقي، موسيقى أفلام ومشاريع موسيقية مؤسسية.',
'meta-index-description' => 'اكتشف ألبوماتنا وسينغلاتنا ومشاريع الإنتاج المنشورة على Spotify وYouTube والمنصات الرقمية.',
'empty' => 'لا يوجد إنتاج موسيقي مسجّل حتى الآن.',
'search_placeholder' => 'ابحث بالعنوان أو اسم العميل…',
'search_no_results' => 'لا توجد نتائج لـ ":query".',
'card_category_default' => 'إنتاج',
'production_date_unknown' => 'التاريخ غير محدد',
'view_details_tooltip' => 'عرض التفاصيل',
'project_details' => 'تفاصيل المشروع',
'back_to_list' => 'العودة إلى القائمة',
'prev' => 'السابق',
'next' => 'التالي',
// Module labels
'title' => 'الإنتاج الموسيقي',
'navigation_label' => 'إنتاج موسيقي',
'model_label' => 'إنتاج موسيقي',
'plural_model_label' => 'إنتاجات موسيقية',
// Actions
'create' => 'إنشاء إنتاج موسيقي جديد',
'edit' => 'تعديل الإنتاج الموسيقي',
'save' => 'حفظ',
'cancel' => 'إلغاء',
'delete' => 'حذف الإنتاج الموسيقي',
'restore' => 'استعادة الإنتاج الموسيقي',
'force_delete' => 'حذف نهائي',
// Form fields
'title_field' => 'العنوان',
'slug_field' => 'مسار URL',
'content_field' => 'المحتوى',
'client_name_field' => 'اسم العميل',
'production_date_field' => 'تاريخ الإنتاج',
'cover_image_field' => 'صورة الغلاف',
'gallery_field' => 'صور المعرض',
'is_active_field' => 'نشط؟',
'sort_order_field' => 'ترتيب الفرز',
// Sections
'content_section' => 'المحتوى',
'settings_section' => 'إعدادات الإنتاج',
'translations_section' => 'الترجمات',
// Helper texts
'slug_helper' => 'الجزء الذي سيظهر في URL. مثال: music-production-1',
'cover_image_helper' => 'اختر صورة غلاف للإنتاج',
'gallery_helper' => 'اختر صورًا أخرى للإنتاج (يدعم الرفع المتعدد)',
'production_date_helper' => 'تاريخ اكتمال الإنتاج',
'is_active_helper' => 'عرض هذا الإنتاج الموسيقي على الموقع',
'sort_order_helper' => 'أدخل رقم ترتيب لأولوية القائمة',
// Status options
'status_draft' => 'مسودة',
'status_published' => 'منشور',
'status_archived' => 'مؤرشف',
// Messages
'created_successfully' => 'تم إنشاء الإنتاج الموسيقي بنجاح.',
'updated_successfully' => 'تم تحديث الإنتاج الموسيقي بنجاح.',
'deleted_successfully' => 'تم حذف الإنتاج الموسيقي بنجاح.',
'restored_successfully' => 'تم استعادة الإنتاج الموسيقي بنجاح.',
// Table columns
'table_title' => 'العنوان',
'table_slug' => 'مسار URL',
'table_client_name' => 'العميل',
'table_production_date' => 'تاريخ الإنتاج',
'table_status' => 'الحالة',
'table_is_active' => 'نشط',
'table_created_at' => 'تاريخ الإنشاء',
'table_updated_at' => 'تاريخ التحديث',
// Validation messages
'title_required' => 'حقل العنوان إلزامي.',
'slug_required' => 'حقل مسار URL إلزامي.',
'slug_unique' => 'هذا المسار مستخدم بالفعل.',
// Spotify
'spotify_section' => 'معلومات Spotify',
'spotify_album_id_field' => 'معرّف ألبوم Spotify',
'spotify_url_field' => 'رابط Spotify',
'spotify_type_field' => 'نوع Spotify',
'spotify_synced_at_field' => 'آخر مزامنة Spotify',
'spotify_type_album' => 'ألبوم',
'spotify_type_single' => 'سينغل',
'spotify_type_compilation' => 'تجميعة',
'spotify_listen_on_spotify' => 'استمع على Spotify',
'spotify_track_singular' => 'مقطوعة',
'spotify_track_plural' => 'مقطوعات',
'sync_spotify' => 'مزامنة من Spotify',
'sync_spotify_heading' => 'مزامنة Spotify',
'sync_spotify_description' => 'سيتم مزامنة الألبومات والسينغلات من حساب الفنان مع الإنتاجات الموسيقية.',
'spotify_sync_started' => 'جارٍ بدء مزامنة Spotify...',
'spotify_sync_completed' => 'اكتملت المزامنة. :created جديد، :updated محدَّث (الإجمالي :total).',
'spotify_sync_success' => 'اكتملت مزامنة Spotify بنجاح.',
'spotify_sync_failed' => 'فشلت مزامنة Spotify. تحقق من السجلات.',
'spotify_not_configured' => 'بيانات Spotify API مفقودة. حدد SPOTIFY_CLIENT_ID وSPOTIFY_CLIENT_SECRET وSPOTIFY_ARTIST_ID في ملف .env.',
'spotify_token_failed' => 'فشل الحصول على رمز الوصول لـ Spotify.',
'spotify_albums_fetch_failed' => 'فشل جلب قائمة ألبومات Spotify.',
'spotify_premium_required' => 'يحتاج حساب Spotify المطوّر إلى اشتراك Premium نشط. Detail: :detail',
'spotify_no_albums' => 'لم يتم العثور على ألبومات أو سينغلات في حساب فنان Spotify.',
'spotify_untitled_album' => 'ألبوم بلا عنوان',
// YouTube
'youtube_section' => 'معلومات YouTube',
'youtube_video_id_field' => 'معرّف فيديو YouTube',
'youtube_url_field' => 'رابط YouTube',
'youtube_description_field' => 'وصف YouTube',
'youtube_synced_at_field' => 'آخر مزامنة YouTube',
'youtube_watch_on_youtube' => 'شاهد على YouTube',
'sync_youtube' => 'مزامنة من YouTube',
'sync_youtube_heading' => 'مزامنة إصدارات YouTube',
'sync_youtube_description' => 'سيتم مزامنة إصدارات المقاطع الفنية من قائمة تشغيل Releases في قناتك.',
'youtube_sync_started' => 'جارٍ بدء مزامنة إصدارات YouTube...',
'youtube_sync_source' => 'المصدر: :source',
'youtube_sync_completed' => 'اكتملت المزامنة. :created جديد، :updated محدَّث (الإجمالي :total).',
'youtube_sync_success' => 'اكتملت مزامنة YouTube بنجاح.',
'youtube_sync_failed' => 'فشلت مزامنة YouTube. تحقق من السجلات.',
'youtube_not_configured' => 'بيانات YouTube API مفقودة. حدد YOUTUBE_API_KEY وYOUTUBE_CHANNEL_ID في ملف .env.',
'youtube_releases_fetch_failed' => 'فشل جلب قائمة إصدارات YouTube.',
'youtube_referrer_blocked' => 'رفض مفتاح YouTube API الطلب. Detail: :detail',
'youtube_playlist_not_resolved' => 'تعذّر تحليل معرّف قائمة التشغيل. حدد YOUTUBE_CHANNEL_ID أو YOUTUBE_PLAYLIST_ID.',
'youtube_no_releases' => 'لم يتم العثور على إصدارات في قائمة تشغيل YouTube Releases.',
'youtube_untitled_release' => 'إصدار بلا عنوان',
// Metadata table labels
'field' => 'الحقل',
'value' => 'القيمة',
'track' => 'المقطوعة',
'style' => 'الأسلوب',
'contributors' => 'المساهمون',
'released_on' => 'تاريخ الإصدار',
'distributor' => 'الموزع',
'label' => 'التسجيلات',
'youtube' => 'YouTube',
];
+15
View File
@@ -0,0 +1,15 @@
<?php
return [
// Metadata table labels
'field' => 'Feld',
'value' => 'Wert',
'track' => 'Titel',
'style' => 'Stil',
'contributors' => 'Mitwirkende',
'released_on' => 'Veröffentlicht am',
'distributor' => 'Vertriebsfirma',
'label' => 'Label',
'youtube' => 'YouTube',
];
?>
+12
View File
@@ -130,4 +130,16 @@ return [
'youtube_playlist_not_resolved' => 'Could not resolve YouTube Releases playlist ID. Set YOUTUBE_CHANNEL_ID or YOUTUBE_PLAYLIST_ID.',
'youtube_no_releases' => 'No releases found in the YouTube Releases playlist.',
'youtube_untitled_release' => 'Untitled Release',
// Metadata table labels
'field' => 'Field',
'value' => 'Value',
'track' => 'Track',
'style' => 'Style',
'contributors' => 'Contributors',
'released_on' => 'Released on',
'distributor' => 'Distributor',
'label' => 'Label',
'youtube' => 'YouTube',
];
@@ -177,71 +177,67 @@
<div class="xl:w-10/12 xl:!ml-[8.33333333%] lg:w-10/12 lg:!ml-[8.33333333%] w-full flex-[0_0_auto] !px-[15px] max-w-full">
<h2 class="!text-[calc(1.265rem_+_0.18vw)] font-bold xl:!text-[1.4rem] !leading-[1.35] !mb-4">{{ __('music_productions.project_details') }}</h2>
<div class="flex flex-wrap mx-0">
{{-- Content column --}}
<div class="xl:w-9/12 lg:w-9/12 md:w-9/12 w-full flex-[0_0_auto] max-w-full">
<div class="music-production-content prose max-w-none">
{!! $production->translate('content') !!}
</div>
</div>
{{-- Sidebar - Date & Client --}}
<div class="metadata-table w-full max-w-2xl mx-auto my-6">
<table class="w-full border border-gray-200 rounded-md overflow-hidden">
<thead class="bg-gray-100">
<tr>
<th class="px-4 py-2 text-left font-medium text-gray-700">Field</th>
<th class="px-4 py-2 text-left font-medium text-gray-700">Value</th>
</tr>
</thead>
<tbody class="bg-white">
<tr class="border-t">
<td class="px-4 py-2">Track</td>
<td class="px-4 py-2">{{ $trackNameParsed ?? $titlePart }}</td>
</tr>
@if($styleParsed)
<tr class="border-t">
<td class="px-4 py-2">Style</td>
<td class="px-4 py-2">{{ $styleParsed }}</td>
</tr>
@endif
@if(!empty($contributors))
<tr class="border-t">
<td class="px-4 py-2">Contributors</td>
<td class="px-4 py-2">{{ implode(', ', $contributors) }}</td>
</tr>
@endif
@if($releasedOn)
<tr class="border-t">
<td class="px-4 py-2">Released on</td>
<td class="px-4 py-2">{{ $releasedOn }}</td>
</tr>
@endif
@if($distributor)
<tr class="border-t">
<td class="px-4 py-2">Distributor</td>
<td class="px-4 py-2">{{ $distributor }}</td>
</tr>
@endif
@if($label)
<tr class="border-t">
<td class="px-4 py-2">Label</td>
<td class="px-4 py-2">{{ $label }}</td>
</tr>
@endif
@if($production->spotify_url)
<tr class="border-t">
<td class="px-4 py-2">Spotify</td>
<td class="px-4 py-2"><a href="{{ $production->spotify_url }}" target="_blank" rel="noopener noreferrer" class="text-blue-600 underline">{{ __('music_productions.spotify_listen_on_spotify') }}</a></td>
</tr>
@endif
@if($production->youtube_url)
<tr class="border-t">
<td class="px-4 py-2">YouTube</td>
<td class="px-4 py-2"><a href="{{ $production->youtube_url }}" target="_blank" rel="noopener noreferrer" class="text-red-600 underline">{{ __('music_productions.youtube_watch_on_youtube') }}</a></td>
</tr>
@endif
</tbody>
</table>
{{-- Premium Metadata Table --}}
<div class="prod-meta-card">
<table class="prod-meta-table">
<tbody>
<tr>
<td class="prod-meta-label"><i class="uil uil-music"></i> {{ __("music_productions.track") }}</td>
<td class="prod-meta-value">{{ $trackNameParsed ?? $titlePart }}</td>
</tr>
@if($styleParsed)
<tr>
<td class="prod-meta-label"><i class="uil uil-layer-group"></i> {{ __("music_productions.style") }}</td>
<td class="prod-meta-value"><span class="prod-meta-badge">{{ $styleParsed }}</span></td>
</tr>
@endif
@if(!empty($contributors))
<tr>
<td class="prod-meta-label"><i class="uil uil-users-alt"></i> {{ __("music_productions.contributors") }}</td>
<td class="prod-meta-value">{{ implode(', ', $contributors) }}</td>
</tr>
@endif
@if($releasedOn)
<tr>
<td class="prod-meta-label"><i class="uil uil-calendar-alt"></i> {{ __("music_productions.released_on") }}</td>
<td class="prod-meta-value">{{ $releasedOn }}</td>
</tr>
@endif
@if($label)
<tr>
<td class="prod-meta-label"><i class="uil uil-record-audio"></i> {{ __("music_productions.label") }}</td>
<td class="prod-meta-value">{{ $label }}</td>
</tr>
@endif
@if($production->spotify_url)
<tr>
<td class="prod-meta-label"><i class="uil uil-headphones"></i> Spotify</td>
<td class="prod-meta-value">
<a href="{{ $production->spotify_url }}" target="_blank" rel="noopener noreferrer" class="prod-platform-btn prod-platform-btn--spotify">
<svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.779-.179-.899-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.301 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.419 1.56-.299.421-1.02.599-1.559.3z"/></svg>
{{ __('music_productions.spotify_listen_on_spotify') }}
</a>
</td>
</tr>
@endif
@if($production->youtube_url)
<tr>
<td class="prod-meta-label"><i class="uil uil-youtube"></i> {{ __("music_productions.youtube") }}</td>
<td class="prod-meta-value">
<a href="{{ $production->youtube_url }}" target="_blank" rel="noopener noreferrer" class="prod-platform-btn prod-platform-btn--youtube">
<svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/></svg>
{{ __('music_productions.youtube_watch_on_youtube') }}
</a>
</td>
</tr>
@endif
</tbody>
</table>
</div>
</div>
@@ -749,6 +745,143 @@ body.lightbox-open .player {
perspective: none !important;
z-index: 1 !important;
}
/* ===== Premium Metadata Table ===== */
.prod-meta-card {
margin: 2.5rem auto;
max-width: 720px;
border-radius: 14px;
overflow: hidden;
box-shadow: 0 4px 24px rgba(30, 34, 40, 0.08);
border: 1px solid rgba(164,174,198,0.18);
background: #fff;
}
.prod-meta-table {
width: 100%;
border-collapse: collapse;
font-size: 0.9rem;
}
.prod-meta-table thead tr {
background: linear-gradient(90deg, #343f52 0%, #4a5568 100%);
color: #fff;
}
.prod-meta-table thead th {
padding: 0.85rem 1.25rem;
text-align: left;
font-weight: 600;
font-size: 0.78rem;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.prod-meta-table thead th i {
margin-right: 0.4rem;
opacity: 0.8;
}
.prod-meta-table tbody tr {
transition: background 0.18s ease;
border-bottom: 1px solid rgba(164,174,198,0.12);
}
.prod-meta-table tbody tr:last-child {
border-bottom: none;
}
.prod-meta-table tbody tr:nth-child(even) {
background: #f8f9fc;
}
.prod-meta-table tbody tr:hover {
background: #eef1f9;
}
.prod-meta-label {
padding: 0.85rem 1.25rem;
font-weight: 600;
color: #343f52;
white-space: nowrap;
width: 36%;
vertical-align: middle;
}
.prod-meta-label i {
margin-right: 0.45rem;
color: #e31e24;
font-size: 1rem;
vertical-align: middle;
}
.prod-meta-value {
padding: 0.85rem 1.25rem;
color: #60697b;
vertical-align: middle;
line-height: 1.6;
}
.prod-meta-badge {
display: inline-block;
padding: 0.2em 0.75em;
border-radius: 50rem;
background: rgba(116, 126, 209, 0.12);
color: #747ed1;
font-size: 0.82rem;
font-weight: 600;
letter-spacing: 0.02em;
}
.prod-platform-btn {
display: inline-flex;
align-items: center;
gap: 0.45rem;
padding: 0.38rem 1rem;
border-radius: 50rem;
font-size: 0.82rem;
font-weight: 600;
text-decoration: none !important;
transition: all 0.22s ease;
border: 1.5px solid transparent;
}
.prod-platform-btn--spotify {
background: rgba(30, 215, 96, 0.1);
color: #1db954;
border-color: rgba(30, 215, 96, 0.25);
}
.prod-platform-btn--spotify:hover {
background: #1db954;
color: #fff !important;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(30, 215, 96, 0.35);
}
.prod-platform-btn--youtube {
background: rgba(227, 30, 36, 0.08);
color: #e31e24;
border-color: rgba(227, 30, 36, 0.2);
}
.prod-platform-btn--youtube:hover {
background: #e31e24;
color: #fff !important;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(227, 30, 36, 0.35);
}
@media (max-width: 576px) {
.prod-meta-table {
display: block;
overflow-x: auto;
}
.prod-meta-label {
width: auto;
white-space: normal;
}
}
</style>
@endpush