114 lines
5.9 KiB
PHP
114 lines
5.9 KiB
PHP
@extends('layouts.app')
|
||
|
||
@section('title', 'Content Board')
|
||
@section('page-title', 'Content Board 🎬')
|
||
@section('page-subtitle', 'Drag cards between columns to update status')
|
||
|
||
@section('content')
|
||
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-5">
|
||
<div class="flex gap-2 flex-wrap">
|
||
<a href="{{ route('content.create') }}" class="btn-sakura text-sm shrink-0">+ New Brief</a>
|
||
@foreach(['instagram', 'tiktok', 'youtube'] as $p)
|
||
<a href="{{ request()->fullUrlWithQuery(['platform' => $p]) }}"
|
||
class="px-3 py-1.5 rounded-full text-xs font-semibold transition-colors
|
||
{{ request('platform') === $p ? 'text-white' : 'bg-white text-gray-500 hover:bg-pink-50 border border-pink-100' }}"
|
||
style="{{ request('platform') === $p ? 'background:#FFB7C5' : '' }}">
|
||
{{ ['instagram' => '📸', 'tiktok' => '🎵', 'youtube' => '▶️'][$p] }} {{ ucfirst($p) }}
|
||
</a>
|
||
@endforeach
|
||
@if(request('platform'))
|
||
<a href="{{ route('content.index') }}"
|
||
class="px-3 py-1.5 rounded-full text-xs text-gray-400 hover:text-gray-600 border border-gray-200 bg-white">✕
|
||
Clear</a>
|
||
@endif
|
||
</div>
|
||
|
||
</div>
|
||
|
||
{{--
|
||
Mobile : grid grid-cols-1 → columns stack vertically, each full width
|
||
Desktop : flex flex-nowrap → columns in a single horizontal row, each flex-1
|
||
x-sort:group is on the INNER items div (not the column div) to avoid
|
||
SortableJS mutating the outer layout container.
|
||
--}}
|
||
<div class="grid grid-cols-1 gap-4 lg:flex lg:flex-nowrap lg:gap-4" x-data="kanban()">
|
||
@foreach($columns as $col)
|
||
@php $status = $col['status']; @endphp
|
||
|
||
{{-- Column shell — layout only, NOT the sort target --}}
|
||
<div class="{{ $status->colorClass() }} flex flex-col w-full lg:flex-1 lg:min-w-36 rounded-2xl p-3"
|
||
data-status="{{ $status->value }}">
|
||
|
||
{{-- Column header --}}
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div class="flex items-center gap-1.5">
|
||
<span class="text-base">{{ $status->icon() }}</span>
|
||
<span class="font-bold text-gray-700 text-sm">{{ $status->label() }}</span>
|
||
</div>
|
||
<span
|
||
class="text-xs bg-white rounded-full px-2 py-0.5 font-bold text-gray-500 shadow-sm">{{ count($col['items']) }}</span>
|
||
</div>
|
||
|
||
{{-- Sortable items container --}}
|
||
<div class="flex flex-col gap-2 flex-1 min-h-12" x-sort:group="kanban"
|
||
@sort="moved($event, '{{ $status->value }}')" data-col-status="{{ $status->value }}">
|
||
|
||
@foreach($col['items'] as $brief)
|
||
<div class="bg-white rounded-2xl p-3 shadow-sm border border-pink-50 select-none
|
||
cursor-grab active:cursor-grabbing hover:shadow-md transition-shadow"
|
||
x-sort:item="{{ $brief->id }}" data-id="{{ $brief->id }}">
|
||
<div class="flex items-start gap-2 mb-1.5">
|
||
<span class="text-sm shrink-0">{{ $brief->platform_icon }}</span>
|
||
<a href="{{ route('content.show', $brief) }}"
|
||
class="font-semibold text-gray-800 text-xs leading-tight hover:text-pink-500 line-clamp-2 flex-1">
|
||
{{ $brief->title }}
|
||
</a>
|
||
</div>
|
||
@if($brief->client)
|
||
<div class="text-xs text-gray-400 mb-1">👥 {{ $brief->client->name }}</div>
|
||
@endif
|
||
@if($brief->target_date)
|
||
<div
|
||
class="text-xs {{ $brief->target_date->isPast() && $brief->status->value !== 'posted' ? 'text-red-400 font-bold' : 'text-gray-400' }}">
|
||
📅 {{ $brief->target_date->format('d M') }}
|
||
</div>
|
||
@endif
|
||
<div class="flex justify-end mt-1.5">
|
||
<a href="{{ route('content.edit', $brief) }}"
|
||
class="text-xs text-gray-400 hover:text-pink-500">Edit</a>
|
||
</div>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
|
||
{{-- Add button --}}
|
||
<a href="{{ route('content.create') }}?status={{ $status->value }}"
|
||
class="mt-3 text-xs text-gray-400 hover:text-pink-500 text-center py-2
|
||
border-2 border-dashed border-pink-100 rounded-2xl hover:border-pink-300 transition-colors block">
|
||
+ Add
|
||
</a>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
|
||
@push('scripts')
|
||
<script>
|
||
function kanban() {
|
||
return {
|
||
moved(event, targetStatus) {
|
||
const id = event.item?.dataset?.id;
|
||
if (!id) return;
|
||
fetch(`/content/${id}/status`, {
|
||
method: 'PATCH',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
||
},
|
||
body: JSON.stringify({ status: targetStatus }),
|
||
}).then(r => { if (r.ok) window.KolManager.notify('Status updated! 🎬'); });
|
||
},
|
||
};
|
||
}
|
||
</script>
|
||
@endpush
|
||
@endsection |