user-artikel final done

This commit is contained in:
E31232303evimr 2026-03-16 09:13:58 +07:00
parent b979707a4a
commit 54e82c61a7
10 changed files with 2126 additions and 378 deletions

View File

@ -4,6 +4,7 @@
use App\Http\Controllers\Controller;
use App\Models\InformasiBudidaya;
use App\Models\BudidayaSub;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
@ -25,12 +26,15 @@ public function store(Request $request)
$validated = $request->validate([
'judul' => 'required|string|max:200',
'deskripsi_singkat' => 'nullable|string',
'konten' => 'required|string',
'konten' => 'nullable|string',
'gambar_utama' => 'nullable|image|max:2048',
'galeri_gambar.*' => 'nullable|image|max:2048',
'file_pdf' => 'nullable|mimes:pdf|max:5120',
'tags' => 'nullable|string',
'is_published' => 'boolean',
'sub_judul.*' => 'nullable|string|max:200',
'sub_konten.*' => 'nullable|string',
'sub_gambar.*' => 'nullable|image|max:2048',
]);
$validated['slug'] = Str::slug($request->judul);
@ -45,16 +49,14 @@ public function store(Request $request)
$validated['file_pdf'] = $request->file('file_pdf')->store('budidaya/pdf', 'public');
}
// Handle galeri gambar
if ($request->hasFile('galeri_gambar')) {
$galeri = [];
foreach ($request->file('galeri_gambar') as $foto) {
$galeri[] = $foto->store('budidaya/galeri', 'public');
}
$validated['galeri_gambar'] = $galeri; // otomatis di-cast ke JSON oleh model
$validated['galeri_gambar'] = $galeri;
}
// Handle tags
$tagsDecoded = json_decode($request->tags, true);
$validated['tags'] = (!empty($tagsDecoded)) ? $tagsDecoded : null;
@ -62,7 +64,28 @@ public function store(Request $request)
$validated['published_at'] = now();
}
InformasiBudidaya::create($validated);
$artikel = InformasiBudidaya::create($validated);
// Handle sub-bab
if ($request->has('sub_judul')) {
foreach ($request->sub_judul as $index => $judul) {
if (!empty($judul)) {
$subData = [
'id_artikel' => $artikel->id,
'judul_sub' => $judul,
'konten' => $request->sub_konten[$index] ?? null,
'urutan' => $index + 1,
];
if ($request->hasFile("sub_gambar.$index")) {
$path = $request->file("sub_gambar.$index")->store('budidaya/sub', 'public');
$subData['gambar'] = $path;
}
BudidayaSub::create($subData);
}
}
}
return redirect()->route('admin.artikel-budidaya.index')
->with('success', 'Artikel budidaya berhasil ditambahkan!');
@ -70,6 +93,7 @@ public function store(Request $request)
public function edit(InformasiBudidaya $artikelBudidaya)
{
$artikelBudidaya->load('subBab');
return view('admin.artikel-budidaya.edit', compact('artikelBudidaya'));
}
@ -78,12 +102,15 @@ public function update(Request $request, InformasiBudidaya $artikelBudidaya)
$validated = $request->validate([
'judul' => 'required|string|max:200',
'deskripsi_singkat' => 'nullable|string',
'konten' => 'required|string',
'konten' => 'nullable|string',
'gambar_utama' => 'nullable|image|max:2048',
'galeri_gambar.*' => 'nullable|image|max:2048',
'file_pdf' => 'nullable|mimes:pdf|max:5120',
'tags' => 'nullable|string',
'is_published' => 'boolean',
'sub_judul.*' => 'nullable|string|max:200',
'sub_konten.*' => 'nullable|string',
'sub_gambar.*' => 'nullable|image|max:2048',
]);
$validated['slug'] = Str::slug($request->judul);
@ -97,7 +124,6 @@ public function update(Request $request, InformasiBudidaya $artikelBudidaya)
$validated['file_pdf'] = $request->file('file_pdf')->store('budidaya/pdf', 'public');
}
// Handle galeri gambar
if ($request->hasFile('galeri_gambar')) {
$galeri = [];
foreach ($request->file('galeri_gambar') as $foto) {
@ -106,7 +132,6 @@ public function update(Request $request, InformasiBudidaya $artikelBudidaya)
$validated['galeri_gambar'] = $galeri;
}
// Handle tags
$tagsDecoded = json_decode($request->tags, true);
$validated['tags'] = (!empty($tagsDecoded)) ? $tagsDecoded : null;
@ -116,6 +141,29 @@ public function update(Request $request, InformasiBudidaya $artikelBudidaya)
$artikelBudidaya->update($validated);
// Hapus sub-bab lama & simpan yang baru
$artikelBudidaya->subBab()->delete();
if ($request->has('sub_judul')) {
foreach ($request->sub_judul as $index => $judul) {
if (!empty($judul)) {
$subData = [
'id_artikel' => $artikelBudidaya->id,
'judul_sub' => $judul,
'konten' => $request->sub_konten[$index] ?? null,
'urutan' => $index + 1,
];
if ($request->hasFile("sub_gambar.$index")) {
$path = $request->file("sub_gambar.$index")->store('budidaya/sub', 'public');
$subData['gambar'] = $path;
}
BudidayaSub::create($subData);
}
}
}
return redirect()->route('admin.artikel-budidaya.index')
->with('success', 'Artikel budidaya berhasil diupdate!');
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class BudidayaSub extends Model
{
protected $table = 'budidaya_sub';
protected $fillable = [
'id_artikel',
'judul_sub',
'konten',
'gambar',
'urutan',
];
public function artikel()
{
return $this->belongsTo(InformasiBudidaya::class, 'id_artikel', 'id');
}
}

View File

@ -41,4 +41,9 @@ public function scopePublished($query)
{
return $query->where('is_published', true);
}
public function subBab()
{
return $this->hasMany(BudidayaSub::class, 'id_artikel', 'id')->orderBy('urutan');
}
}

View File

@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('budidaya_sub', function (Blueprint $table) {
$table->id();
$table->foreignId('id_artikel')->constrained('informasi_budidaya')->onDelete('cascade');
$table->string('judul_sub');
$table->longText('konten')->nullable();
$table->string('gambar')->nullable();
$table->integer('urutan')->default(0);
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('budidaya_sub');
}
};

View File

@ -12,10 +12,10 @@
<div class="space-y-6">
<!-- Judul -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Judul <span class="text-red-500">*</span></label>
<label class="block text-sm font-bold text-gray-700 mb-2">Judul Bab <span class="text-red-500">*</span></label>
<input type="text" name="judul" value="{{ old('judul') }}"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500 focus:border-transparent @error('judul') border-red-500 @enderror"
placeholder="Masukkan judul artikel...">
placeholder="Contoh: Persiapan Lahan, Penanaman, dll...">
@error('judul') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
@ -24,22 +24,13 @@ class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:rin
<label class="block text-sm font-bold text-gray-700 mb-2">Deskripsi Singkat</label>
<textarea name="deskripsi_singkat" rows="3"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500 focus:border-transparent"
placeholder="Ringkasan singkat artikel...">{{ old('deskripsi_singkat') }}</textarea>
</div>
<!-- Konten -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Konten <span class="text-red-500">*</span></label>
<textarea name="konten" rows="10"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500 focus:border-transparent @error('konten') border-red-500 @enderror"
placeholder="Tulis konten artikel di sini...">{{ old('konten') }}</textarea>
@error('konten') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
placeholder="Ringkasan singkat tentang bab ini...">{{ old('deskripsi_singkat') }}</textarea>
</div>
<!-- Gambar Utama & PDF -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Gambar Utama</label>
<label class="block text-sm font-bold text-gray-700 mb-2">Gambar Cover</label>
<input type="file" name="gambar_utama" accept="image/*"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500">
<p class="text-xs text-gray-400 mt-1">Format: JPG, PNG. Maks 2MB</p>
@ -55,8 +46,7 @@ class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:rin
<!-- Tags -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Tags</label>
<div id="tags-container" class="w-full px-4 py-3 border border-gray-300 rounded-xl flex flex-wrap gap-2 min-h-[50px]">
</div>
<div id="tags-container" class="w-full px-4 py-3 border border-gray-300 rounded-xl flex flex-wrap gap-2 min-h-[50px]"></div>
<input type="text" id="tags-input"
class="w-full mt-2 px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500"
placeholder="Ketik tag lalu tekan Enter...">
@ -64,12 +54,26 @@ class="w-full mt-2 px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focu
<input type="hidden" name="tags" id="tags-hidden" value="[]">
</div>
<!-- Galeri Gambar -->
<!-- Sub-bab -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Galeri Gambar</label>
<input type="file" name="galeri_gambar[]" accept="image/*" multiple
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500">
<p class="text-xs text-gray-400 mt-1">Bisa pilih beberapa foto sekaligus. Format: JPG, PNG. Maks 2MB per foto</p>
<div class="flex items-center justify-between mb-4">
<div>
<label class="block text-sm font-bold text-gray-700">Sub-bab</label>
<p class="text-xs text-gray-400 mt-1">Tambahkan sub-bab untuk artikel ini</p>
</div>
<button type="button" onclick="tambahSub()"
class="flex items-center gap-2 px-4 py-2 bg-green-500 text-white text-sm font-bold rounded-xl hover:bg-green-600 transition">
+ Tambah Sub-bab
</button>
</div>
<div id="sub-container" class="space-y-4">
<!-- Sub-bab items akan ditambahkan di sini -->
</div>
<div id="empty-sub" class="text-center py-8 bg-gray-50 rounded-xl border-2 border-dashed border-gray-200">
<p class="text-gray-400 text-sm">Belum ada sub-bab. Klik tombol di atas untuk menambahkan.</p>
</div>
</div>
<!-- Status Publish -->
@ -96,6 +100,53 @@ class="w-5 h-5 text-green-600 rounded focus:ring-green-500">
@push('scripts')
<script>
let subCount = 0;
function tambahSub() {
const container = document.getElementById('sub-container');
const empty = document.getElementById('empty-sub');
empty.classList.add('hidden');
const index = subCount++;
const div = document.createElement('div');
div.className = 'sub-item bg-gray-50 border border-gray-200 rounded-xl p-5 space-y-4';
div.id = `sub-${index}`;
div.innerHTML = `
<div class="flex items-center justify-between">
<h4 class="font-bold text-gray-700 text-sm">Sub-bab ${index + 1}</h4>
<button type="button" onclick="hapusSub(${index})" class="text-red-400 hover:text-red-600 text-sm font-semibold">Hapus</button>
</div>
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">Judul Sub-bab <span class="text-red-500">*</span></label>
<input type="text" name="sub_judul[]"
class="w-full px-4 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-green-500"
placeholder="Contoh: Pemilihan Lahan">
</div>
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">Konten</label>
<textarea name="sub_konten[]" rows="5"
class="w-full px-4 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-green-500"
placeholder="Tulis isi sub-bab di sini..."></textarea>
</div>
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">Gambar (opsional)</label>
<input type="file" name="sub_gambar[${index}]" accept="image/*"
class="w-full px-4 py-2 border border-gray-300 rounded-lg text-sm">
<p class="text-xs text-gray-400 mt-1">Format: JPG, PNG. Maks 2MB</p>
</div>
`;
container.appendChild(div);
}
function hapusSub(index) {
const el = document.getElementById(`sub-${index}`);
if (el) el.remove();
if (document.querySelectorAll('.sub-item').length === 0) {
document.getElementById('empty-sub').classList.remove('hidden');
}
}
// Tags
const tagsInput = document.getElementById('tags-input');
const tagsContainer = document.getElementById('tags-container');
const tagsHidden = document.getElementById('tags-hidden');
@ -130,5 +181,4 @@ function removeTag(index) {
}
});
</script>
@endpush

View File

@ -13,7 +13,7 @@
<div class="space-y-6">
<!-- Judul -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Judul <span class="text-red-500">*</span></label>
<label class="block text-sm font-bold text-gray-700 mb-2">Judul Bab <span class="text-red-500">*</span></label>
<input type="text" name="judul" value="{{ old('judul', $artikelBudidaya->judul) }}"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500 focus:border-transparent @error('judul') border-red-500 @enderror">
@error('judul') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
@ -26,24 +26,16 @@ class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:rin
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500 focus:border-transparent">{{ old('deskripsi_singkat', $artikelBudidaya->deskripsi_singkat) }}</textarea>
</div>
<!-- Konten -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Konten <span class="text-red-500">*</span></label>
<textarea name="konten" rows="10"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500 focus:border-transparent @error('konten') border-red-500 @enderror">{{ old('konten', $artikelBudidaya->konten) }}</textarea>
@error('konten') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<!-- Gambar Utama -->
<!-- Gambar Utama & PDF -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Gambar Utama</label>
<label class="block text-sm font-bold text-gray-700 mb-2">Gambar Cover</label>
@if($artikelBudidaya->gambar_utama)
<img src="{{ Storage::url($artikelBudidaya->gambar_utama) }}" class="w-32 h-24 object-cover rounded-lg mb-2">
@endif
<input type="file" name="gambar_utama" accept="image/*"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500">
<p class="text-xs text-gray-400 mt-1">Kosongkan jika tidak ingin mengubah gambar</p>
<p class="text-xs text-gray-400 mt-1">Kosongkan jika tidak ingin mengubah</p>
</div>
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">File PDF</label>
@ -52,36 +44,74 @@ class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:rin
@endif
<input type="file" name="file_pdf" accept=".pdf"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500">
<p class="text-xs text-gray-400 mt-1">Kosongkan jika tidak ingin mengubah PDF</p>
<p class="text-xs text-gray-400 mt-1">Kosongkan jika tidak ingin mengubah</p>
</div>
</div>
<!-- Tags -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Tags</label>
<div id="tags-container" class="w-full px-4 py-3 border border-gray-300 rounded-xl flex flex-wrap gap-2 min-h-[50px]">
</div>
<div id="tags-container" class="w-full px-4 py-3 border border-gray-300 rounded-xl flex flex-wrap gap-2 min-h-[50px]"></div>
<input type="text" id="tags-input"
class="w-full mt-2 px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500"
placeholder="Ketik tag lalu tekan Enter...">
<p class="text-xs text-gray-400 mt-1">Tekan Enter atau koma untuk menambah tag</p>
<input type="hidden" name="tags" id="tags-hidden" value="[]">
</div>
<!-- Galeri Gambar -->
<!-- Sub-bab -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Galeri Gambar</label>
@if($artikelBudidaya->galeri_gambar)
<div class="flex flex-wrap gap-2 mb-3">
@foreach($artikelBudidaya->galeri_gambar as $foto)
<img src="{{ Storage::url($foto) }}" class="w-24 h-20 object-cover rounded-lg">
<div class="flex items-center justify-between mb-4">
<div>
<label class="block text-sm font-bold text-gray-700">Sub-bab</label>
<p class="text-xs text-gray-400 mt-1">Edit atau tambah sub-bab</p>
</div>
<button type="button" onclick="tambahSub()"
class="flex items-center gap-2 px-4 py-2 bg-green-500 text-white text-sm font-bold rounded-xl hover:bg-green-600 transition">
+ Tambah Sub-bab
</button>
</div>
<div id="sub-container" class="space-y-4">
@foreach($artikelBudidaya->subBab as $i => $sub)
<div class="sub-item bg-gray-50 border border-gray-200 rounded-xl p-5 space-y-4" id="sub-existing-{{ $i }}">
<div class="flex items-center justify-between">
<h4 class="font-bold text-gray-700 text-sm">Sub-bab {{ $i + 1 }}</h4>
<button type="button" onclick="hapusSubExisting('sub-existing-{{ $i }}')" class="text-red-400 hover:text-red-600 text-sm font-semibold">Hapus</button>
</div>
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">Judul Sub-bab <span class="text-red-500">*</span></label>
<input type="text" name="sub_judul[]" value="{{ $sub->judul_sub }}"
class="w-full px-4 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-green-500">
</div>
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">Konten</label>
<textarea name="sub_konten[]" rows="5"
class="w-full px-4 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-green-500">{{ $sub->konten }}</textarea>
</div>
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">Gambar</label>
@if($sub->gambar)
<img src="{{ Storage::url($sub->gambar) }}" class="w-24 h-16 object-cover rounded-lg mb-2">
@endif
<input type="file" name="sub_gambar[{{ $i }}]" accept="image/*"
class="w-full px-4 py-2 border border-gray-300 rounded-lg text-sm">
<p class="text-xs text-gray-400 mt-1">Kosongkan jika tidak ingin mengubah</p>
</div>
</div>
@endforeach
</div>
@endif
<input type="file" name="galeri_gambar[]" accept="image/*" multiple
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500">
<p class="text-xs text-gray-400 mt-1">Upload foto baru akan menggantikan galeri yang lama</p>
@if($artikelBudidaya->subBab->isEmpty())
<div id="empty-sub" class="text-center py-8 bg-gray-50 rounded-xl border-2 border-dashed border-gray-200">
<p class="text-gray-400 text-sm">Belum ada sub-bab. Klik tombol di atas untuk menambahkan.</p>
</div>
@else
<div id="empty-sub" class="hidden text-center py-8 bg-gray-50 rounded-xl border-2 border-dashed border-gray-200">
<p class="text-gray-400 text-sm">Belum ada sub-bab. Klik tombol di atas untuk menambahkan.</p>
</div>
@endif
</div>
<!-- Status Publish -->
<div class="flex items-center space-x-3">
<input type="checkbox" name="is_published" value="1" id="is_published" {{ old('is_published', $artikelBudidaya->is_published) ? 'checked' : '' }}
@ -106,11 +136,55 @@ class="w-5 h-5 text-green-600 rounded focus:ring-green-500">
@push('scripts')
<script>
let subCount = {{ $artikelBudidaya->subBab->count() }};
function tambahSub() {
const container = document.getElementById('sub-container');
const empty = document.getElementById('empty-sub');
empty.classList.add('hidden');
const index = subCount++;
const div = document.createElement('div');
div.className = 'sub-item bg-gray-50 border border-gray-200 rounded-xl p-5 space-y-4';
div.id = `sub-new-${index}`;
div.innerHTML = `
<div class="flex items-center justify-between">
<h4 class="font-bold text-gray-700 text-sm">Sub-bab Baru</h4>
<button type="button" onclick="hapusSubExisting('sub-new-${index}')" class="text-red-400 hover:text-red-600 text-sm font-semibold">Hapus</button>
</div>
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">Judul Sub-bab <span class="text-red-500">*</span></label>
<input type="text" name="sub_judul[]"
class="w-full px-4 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-green-500"
placeholder="Contoh: Pemilihan Lahan">
</div>
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">Konten</label>
<textarea name="sub_konten[]" rows="5"
class="w-full px-4 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-green-500"
placeholder="Tulis isi sub-bab di sini..."></textarea>
</div>
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">Gambar (opsional)</label>
<input type="file" name="sub_gambar[${index}]" accept="image/*"
class="w-full px-4 py-2 border border-gray-300 rounded-lg text-sm">
</div>
`;
container.appendChild(div);
}
function hapusSubExisting(id) {
const el = document.getElementById(id);
if (el) el.remove();
if (document.querySelectorAll('.sub-item').length === 0) {
document.getElementById('empty-sub').classList.remove('hidden');
}
}
// Tags
const tagsInput = document.getElementById('tags-input');
const tagsContainer = document.getElementById('tags-container');
const tagsHidden = document.getElementById('tags-hidden');
// Load tags yang sudah ada
let tags = {!! json_encode($artikelBudidaya->tags ?? []) !!};
function renderTags() {
@ -142,7 +216,6 @@ function removeTag(index) {
}
});
// Render tags awal
renderTags();
</script>
@endpush

View File

@ -1,89 +1,427 @@
@extends('layouts.user-app')
@section('page-title', '🌱 Artikel Budidaya')
@section('page-title', 'Artikel Budidaya')
@section('page-subtitle', 'Informasi seputar budidaya tanaman kopi')
@push('styles')
<style>
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400&family=DM+Sans:wght@300;400;500;600&display=swap');
.budidaya-page {
font-family: 'DM Sans', sans-serif;
}
/* ── Search Bar ── */
.search-wrap {
background: #fff;
border-radius: 20px;
box-shadow: 0 4px 20px rgba(34,80,34,.08);
padding: 20px 24px;
margin-bottom: 28px;
display: flex;
align-items: center;
gap: 16px;
}
.search-inner {
flex: 1;
position: relative;
}
.search-icon {
position: absolute;
left: 14px;
top: 50%;
transform: translateY(-50%);
color: #9eb89e;
display: flex;
align-items: center;
pointer-events: none;
}
.search-input {
width: 100%;
padding: 12px 16px 12px 44px;
border: 1.5px solid #e0ece0;
border-radius: 12px;
font-size: 13.5px;
font-family: 'DM Sans', sans-serif;
color: #1a2e1a;
background: #f7fbf7;
transition: border-color .2s, box-shadow .2s;
outline: none;
}
.search-input:focus {
border-color: #4caf50;
box-shadow: 0 0 0 3px rgba(76,175,80,.12);
background: #fff;
}
.search-input::placeholder { color: #9eb89e; }
.search-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
background: linear-gradient(135deg, #e8f5e9, #c8e6c9);
border: 1.5px solid #a5d6a7;
border-radius: 100px;
font-size: 12px;
font-weight: 600;
color: #2e7d32;
white-space: nowrap;
}
/* ── Grid ── */
.artikel-grid {
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: 24px;
}
@media (min-width: 768px) {
.artikel-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
.artikel-grid { grid-template-columns: repeat(3, 1fr); }
}
/* ── Card ── */
.artikel-card {
background: #fff;
border-radius: 20px;
box-shadow: 0 4px 20px rgba(34,80,34,.07);
overflow: hidden;
display: flex;
flex-direction: column;
text-decoration: none;
transition: transform .25s ease, box-shadow .25s ease;
border: 1.5px solid #f0f7f0;
}
.artikel-card:hover {
transform: translateY(-6px);
box-shadow: 0 16px 40px rgba(34,80,34,.14);
border-color: #c8e6c9;
}
/* Image */
.card-img-wrap {
height: 200px;
overflow: hidden;
position: relative;
background: linear-gradient(135deg, #a8d5a2, #2e7d32);
}
.card-img-wrap img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform .45s ease;
}
.artikel-card:hover .card-img-wrap img {
transform: scale(1.07);
}
.card-img-overlay {
position: absolute;
inset: 0;
background: linear-gradient(to top, rgba(15,40,15,.45) 0%, transparent 55%);
}
.card-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.card-placeholder span {
font-size: 4rem;
filter: drop-shadow(0 4px 8px rgba(0,0,0,.15));
}
/* Body */
.card-body {
padding: 20px 22px 22px;
flex: 1;
display: flex;
flex-direction: column;
}
/* Tags */
.card-tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-bottom: 12px;
}
.card-tag {
padding: 3px 10px;
background: #e8f5e9;
color: #2e7d32;
border: 1px solid #c8e6c9;
border-radius: 100px;
font-size: 10.5px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: .4px;
}
/* Title */
.card-title {
font-family: 'Lora', serif;
font-weight: 700;
font-size: 1rem;
color: #1a2e1a;
line-height: 1.4;
margin-bottom: 10px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
transition: color .2s;
}
.artikel-card:hover .card-title {
color: #2e7d32;
}
/* Excerpt */
.card-excerpt {
font-size: 12.5px;
color: #6a826a;
line-height: 1.75;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
flex: 1;
margin-bottom: 16px;
}
/* Footer */
.card-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 14px;
border-top: 1px solid #f0f7f0;
margin-top: auto;
}
.card-date {
font-size: 11.5px;
color: #9eb89e;
display: flex;
align-items: center;
gap: 4px;
}
.card-cta {
display: inline-flex;
align-items: center;
gap: 5px;
font-size: 12px;
font-weight: 700;
color: #2e7d32;
padding: 6px 14px;
background: #e8f5e9;
border-radius: 100px;
transition: background .2s, color .2s;
}
.artikel-card:hover .card-cta {
background: #2e7d32;
color: #fff;
}
/* ── Empty State ── */
.empty-state {
background: #fff;
border-radius: 24px;
box-shadow: 0 4px 24px rgba(34,80,34,.08);
padding: 80px 24px;
text-align: center;
}
.empty-state .empty-icon {
font-size: 4rem;
display: block;
margin-bottom: 16px;
opacity: .5;
}
.empty-state h3 {
font-family: 'Lora', serif;
font-size: 1.25rem;
font-weight: 700;
color: #1a2e1a;
margin-bottom: 6px;
}
.empty-state p {
font-size: 13px;
color: #9eb89e;
}
/* ── Pagination ── */
.pagination-wrap {
margin-top: 36px;
display: flex;
justify-content: center;
}
/* ── No result (search) ── */
.no-result-msg {
display: none;
text-align: center;
padding: 48px 24px;
color: #9eb89e;
font-size: 14px;
}
.no-result-msg .nr-icon {
font-size: 3rem;
display: block;
margin-bottom: 10px;
opacity: .5;
}
</style>
@endpush
@section('content')
<!-- Search & Filter -->
<div class="bg-white rounded-2xl shadow-lg p-6 mb-6">
<div class="flex items-center gap-4">
<div class="flex-1 relative">
<span class="absolute left-4 top-3 text-gray-400">🔍</span>
<input type="text" id="search-artikel" placeholder="Cari artikel budidaya..."
class="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-green-500 focus:border-transparent">
<div class="budidaya-page">
{{-- ── Search Bar ── --}}
<div class="search-wrap">
<div class="search-inner">
<span class="search-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.099zm-5.242 1.656a5.5 5.5 0 1 1 0-11 5.5 5.5 0 0 1 0 11"/>
</svg>
</span>
<input
type="text"
id="search-artikel"
class="search-input"
placeholder="Cari artikel budidaya...">
</div>
<div class="search-badge">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">
<path d="M8 16s6-5.686 6-10A6 6 0 0 0 2 6c0 4.314 6 10 6 10m0-7a3 3 0 1 1 0-6 3 3 0 0 1 0 6"/>
</svg>
{{ $artikels->total() }} Artikel
</div>
</div>
<!-- Grid Artikel -->
{{-- ── Grid Artikel ── --}}
@if($artikels->count() > 0)
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" id="artikel-grid">
<div class="artikel-grid" id="artikel-grid">
@foreach($artikels as $artikel)
<a href="{{ route('user.artikel.budidaya.detail', $artikel->slug) }}"
class="artikel-card bg-white rounded-2xl shadow-lg overflow-hidden hover:shadow-xl transition-all hover:-translate-y-1 group">
<!-- Gambar -->
<div class="h-48 bg-gradient-to-br from-green-400 to-green-600 overflow-hidden relative">
<a href="{{ route('user.artikel.budidaya.detail', $artikel->slug) }}" class="artikel-card">
{{-- Gambar --}}
<div class="card-img-wrap">
@if($artikel->gambar_utama)
<img src="{{ Storage::url($artikel->gambar_utama) }}"
class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
alt="{{ $artikel->judul }}">
<img src="{{ Storage::url($artikel->gambar_utama) }}" alt="{{ $artikel->judul }}">
<div class="card-img-overlay"></div>
@else
<div class="w-full h-full flex items-center justify-center">
<span class="text-6xl">🌱</span>
<div class="card-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" fill="rgba(255,255,255,0.6)" viewBox="0 0 16 16">
<path d="M8 16s6-5.686 6-10A6 6 0 0 0 2 6c0 4.314 6 10 6 10m0-7a3 3 0 1 1 0-6 3 3 0 0 1 0 6"/>
</svg>
</div>
@endif
</div>
<!-- Konten -->
<div class="p-5">
<!-- Tags -->
{{-- Body --}}
<div class="card-body">
{{-- Tags --}}
@if($artikel->tags)
<div class="flex flex-wrap gap-1 mb-3">
<div class="card-tags">
@foreach(array_slice($artikel->tags, 0, 2) as $tag)
<span class="px-2 py-0.5 bg-green-100 text-green-700 text-xs font-semibold rounded-full">{{ $tag }}</span>
<span class="card-tag">{{ $tag }}</span>
@endforeach
</div>
@endif
<h3 class="font-bold text-gray-800 mb-2 group-hover:text-green-600 transition-colors line-clamp-2">
{{ $artikel->judul }}
</h3>
{{-- Judul --}}
<h3 class="card-title">{{ $artikel->judul }}</h3>
{{-- Excerpt --}}
@if($artikel->deskripsi_singkat)
<p class="text-xs text-gray-500 leading-relaxed line-clamp-3 mb-4">{{ $artikel->deskripsi_singkat }}</p>
<p class="card-excerpt">{{ $artikel->deskripsi_singkat }}</p>
@endif
<div class="flex items-center justify-between pt-3 border-t border-gray-100">
<span class="text-xs text-gray-400">{{ $artikel->published_at?->format('d M Y') ?? '-' }}</span>
<span class="text-xs font-semibold text-green-600 group-hover:underline">Baca Selengkapnya </span>
{{-- Footer --}}
<div class="card-footer">
<span class="card-date">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5M1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4z"/>
</svg>
{{ $artikel->published_at?->format('d M Y') ?? '-' }}
</span>
<span class="card-cta">Baca &rarr;</span>
</div>
</div>
</a>
@endforeach
</div>
<!-- Pagination -->
<div class="mt-8">{{ $artikels->links() }}</div>
{{-- No result pesan --}}
<div id="no-result" class="no-result-msg">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="#9eb89e" viewBox="0 0 16 16" style="margin:0 auto 10px;display:block;opacity:.5">
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.099zm-5.242 1.656a5.5 5.5 0 1 1 0-11 5.5 5.5 0 0 1 0 11"/>
</svg>
Artikel tidak ditemukan
</div>
{{-- Pagination --}}
<div class="pagination-wrap">
{{ $artikels->links() }}
</div>
@else
<div class="bg-white rounded-2xl shadow-lg p-16 text-center text-gray-400">
<span class="text-6xl block mb-4">🌱</span>
<p class="text-xl font-semibold mb-2">Belum ada artikel budidaya</p>
<p class="text-sm">Artikel akan segera tersedia</p>
<div class="empty-state">
<svg xmlns="http://www.w3.org/2000/svg" width="56" height="56" fill="#9eb89e" viewBox="0 0 16 16" style="margin:0 auto 16px;display:block;opacity:.5">
<path d="M8 16s6-5.686 6-10A6 6 0 0 0 2 6c0 4.314 6 10 6 10m0-7a3 3 0 1 1 0-6 3 3 0 0 1 0 6"/>
</svg>
<h3>Belum ada artikel budidaya</h3>
<p>Artikel akan segera tersedia</p>
</div>
@endif
</div>
@endsection
@push('scripts')
<script>
document.getElementById('search-artikel').addEventListener('input', function () {
const keyword = this.value.toLowerCase();
document.querySelectorAll('.artikel-card').forEach(card => {
const judul = card.querySelector('h3').textContent.toLowerCase();
card.style.display = judul.includes(keyword) ? '' : 'none';
const cards = document.querySelectorAll('.artikel-card');
let visible = 0;
cards.forEach(card => {
const judul = card.querySelector('.card-title').textContent.toLowerCase();
const show = judul.includes(keyword);
card.style.display = show ? '' : 'none';
if (show) visible++;
});
const noResult = document.getElementById('no-result');
if (noResult) noResult.style.display = visible === 0 ? 'block' : 'none';
});
</script>
@endpush

View File

@ -1,111 +1,617 @@
@extends('layouts.user-app')
@section('page-title', '🌱 Artikel Budidaya')
@section('page-subtitle', '{{ $artikel->judul }}')
@section('page-title', 'Artikel Budidaya')
@section('page-subtitle', $artikel->judul)
@push('styles')
<style>
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400&family=DM+Sans:wght@300;400;500;600&display=swap');
.budidaya-wrap {
font-family: 'DM Sans', sans-serif;
}
/* ── Hero Card ── */
.hero-card {
border-radius: 24px;
overflow: hidden;
background: #fff;
box-shadow: 0 4px 24px rgba(34,80,34,.08);
position: relative;
}
.hero-img-wrap {
position: relative;
height: 320px;
overflow: hidden;
}
.hero-img-wrap img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform .6s ease;
}
.hero-card:hover .hero-img-wrap img {
transform: scale(1.03);
}
.hero-img-overlay {
position: absolute;
inset: 0;
background: linear-gradient(to top, rgba(15,40,15,.55) 0%, transparent 55%);
}
.hero-placeholder {
width: 100%;
height: 280px;
background: linear-gradient(135deg, #a8d5a2 0%, #3a8f4a 60%, #1d5c2a 100%);
display: flex;
align-items: center;
justify-content: center;
}
.hero-placeholder span {
font-size: 5rem;
filter: drop-shadow(0 4px 12px rgba(0,0,0,.2));
}
/* ── Tag Pills ── */
.tag-pill {
display: inline-flex;
align-items: center;
padding: 4px 14px;
background: #e8f5e9;
color: #2e7d32;
border: 1.5px solid #a5d6a7;
border-radius: 100px;
font-size: 11px;
font-weight: 600;
letter-spacing: .4px;
text-transform: uppercase;
}
/* ── Article Title ── */
.article-title {
font-family: 'Lora', serif;
font-size: 1.65rem;
font-weight: 700;
color: #1a2e1a;
line-height: 1.35;
letter-spacing: -.3px;
}
.article-meta span {
font-size: 12px;
color: #8a9e8a;
display: inline-flex;
align-items: center;
gap: 4px;
}
.article-excerpt {
background: linear-gradient(135deg, #f1f8f1 0%, #e8f5e9 100%);
border-left: 4px solid #4caf50;
border-radius: 0 12px 12px 0;
padding: 16px 20px;
color: #3d5c3d;
font-style: italic;
font-size: 13.5px;
line-height: 1.7;
}
/* ── Accordion Section ── */
.section-card {
background: #fff;
border-radius: 24px;
box-shadow: 0 4px 24px rgba(34,80,34,.08);
overflow: hidden;
}
.section-header {
padding: 22px 28px;
border-bottom: 1px solid #f0f5f0;
display: flex;
align-items: center;
gap: 10px;
}
.section-header-icon {
width: 36px;
height: 36px;
background: #e8f5e9;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
flex-shrink: 0;
}
.section-header h3 {
font-family: 'Lora', serif;
font-weight: 600;
font-size: 1rem;
color: #1a2e1a;
margin: 0;
}
/* Accordion Item */
.accordion-item {
border-bottom: 1px solid #f3f7f3;
transition: background .2s;
}
.accordion-item:last-child {
border-bottom: none;
}
.accordion-trigger {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 18px 28px;
background: none;
border: none;
cursor: pointer;
text-align: left;
gap: 14px;
transition: background .2s;
}
.accordion-trigger:hover {
background: #f7fbf7;
}
.accordion-trigger:hover .acc-num {
background: #2e7d32;
color: #fff;
}
.acc-num {
width: 32px;
height: 32px;
border-radius: 50%;
background: #e8f5e9;
color: #2e7d32;
font-size: 12px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: background .2s, color .2s;
}
.acc-title {
font-weight: 600;
font-size: 14px;
color: #1a2e1a;
flex: 1;
}
.acc-arrow {
width: 20px;
height: 20px;
color: #8a9e8a;
flex-shrink: 0;
transition: transform .3s ease;
}
.accordion-body {
padding: 0 28px 24px 74px;
display: none;
}
.accordion-body.open {
display: block;
animation: fadeSlideIn .25s ease;
}
@keyframes fadeSlideIn {
from { opacity: 0; transform: translateY(-6px); }
to { opacity: 1; transform: translateY(0); }
}
.accordion-body img {
width: 100%;
max-height: 260px;
object-fit: cover;
border-radius: 14px;
margin-bottom: 14px;
box-shadow: 0 4px 16px rgba(0,0,0,.08);
}
.accordion-body .konten-text {
font-size: 13.5px;
color: #4a5e4a;
line-height: 1.8;
white-space: pre-line;
}
.acc-empty {
font-size: 13px;
color: #9e9e9e;
font-style: italic;
}
/* ── Empty State ── */
.empty-state {
background: #fff;
border-radius: 24px;
box-shadow: 0 4px 24px rgba(34,80,34,.08);
padding: 64px 24px;
text-align: center;
color: #9e9e9e;
}
.empty-state .empty-icon {
font-size: 3.5rem;
display: block;
margin-bottom: 12px;
opacity: .6;
}
.empty-state p {
font-size: 14px;
font-weight: 600;
margin: 0;
}
/* ── Sidebar ── */
.sidebar-card {
background: #fff;
border-radius: 20px;
box-shadow: 0 4px 24px rgba(34,80,34,.08);
padding: 24px;
}
.sidebar-card h3 {
font-family: 'Lora', serif;
font-size: .95rem;
font-weight: 600;
color: #1a2e1a;
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 18px;
}
.sidebar-icon {
width: 32px;
height: 32px;
border-radius: 9px;
display: flex;
align-items: center;
justify-content: center;
font-size: 15px;
flex-shrink: 0;
}
/* TOC */
.toc-btn {
width: 100%;
display: flex;
align-items: center;
gap: 10px;
padding: 8px 10px;
border-radius: 10px;
background: none;
border: none;
cursor: pointer;
text-align: left;
transition: background .2s;
}
.toc-btn:hover {
background: #f1f8f1;
}
.toc-num {
width: 22px;
height: 22px;
border-radius: 50%;
background: #e8f5e9;
color: #2e7d32;
font-size: 10px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: background .2s, color .2s;
}
.toc-btn:hover .toc-num {
background: #4caf50;
color: #fff;
}
.toc-label {
font-size: 12.5px;
color: #4a5e4a;
line-height: 1.4;
}
.toc-btn:hover .toc-label {
color: #2e7d32;
}
/* Info rows */
.info-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0;
border-bottom: 1px solid #f3f7f3;
font-size: 12.5px;
}
.info-row:last-of-type {
border-bottom: none;
}
.info-row .lbl { color: #8a9e8a; }
.info-row .val { font-weight: 600; color: #1a2e1a; }
.info-row .val.green { color: #2e7d32; }
.info-row .val.blue { color: #1565c0; }
/* PDF Button */
.btn-pdf {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 12px 20px;
background: linear-gradient(135deg, #e53935, #b71c1c);
color: #fff;
font-weight: 600;
font-size: 13px;
border-radius: 12px;
text-decoration: none;
margin-top: 14px;
transition: opacity .2s, transform .15s;
box-shadow: 0 4px 12px rgba(183,28,28,.25);
}
.btn-pdf:hover {
opacity: .9;
transform: translateY(-1px);
}
/* Nav Buttons */
.btn-nav {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 12px 20px;
border: 2px solid #e0ece0;
color: #3d5c3d;
font-weight: 600;
font-size: 13px;
border-radius: 12px;
text-decoration: none;
transition: background .2s, border-color .2s, transform .15s;
background: #fff;
}
.btn-nav:hover {
background: #f1f8f1;
border-color: #a5d6a7;
transform: translateY(-1px);
}
/* Sticky sidebar on desktop */
@media (min-width: 1024px) {
.sidebar-sticky {
position: sticky;
top: 24px;
}
}
</style>
@endpush
@section('content')
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div class="budidaya-wrap grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Konten Utama -->
{{-- ══════════════════════════════════
KONTEN UTAMA
══════════════════════════════════ --}}
<div class="lg:col-span-2 space-y-6">
<div class="bg-white rounded-2xl shadow-lg overflow-hidden">
<!-- Gambar -->
{{-- Header Artikel --}}
<div class="hero-card">
{{-- Gambar --}}
@if($artikel->gambar_utama)
<img src="{{ Storage::url($artikel->gambar_utama) }}" class="w-full h-64 object-cover" alt="{{ $artikel->judul }}">
<div class="hero-img-wrap">
<img src="{{ Storage::url($artikel->gambar_utama) }}" alt="{{ $artikel->judul }}">
<div class="hero-img-overlay"></div>
</div>
@else
<div class="w-full h-48 bg-gradient-to-br from-green-400 to-green-600 flex items-center justify-center">
<span class="text-7xl">🌱</span>
<div class="hero-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" fill="rgba(255,255,255,0.7)" viewBox="0 0 16 16">
<path d="M8 16s6-5.686 6-10A6 6 0 0 0 2 6c0 4.314 6 10 6 10m0-7a3 3 0 1 1 0-6 3 3 0 0 1 0 6"/>
</svg>
</div>
@endif
<div class="p-8">
<!-- Tags -->
{{-- Tags --}}
@if($artikel->tags)
<div class="flex flex-wrap gap-2 mb-4">
@foreach($artikel->tags as $tag)
<span class="px-3 py-1 bg-green-100 text-green-700 text-xs font-bold rounded-full">{{ $tag }}</span>
<span class="tag-pill">{{ $tag }}</span>
@endforeach
</div>
@endif
<h1 class="text-2xl font-bold text-gray-800 mb-2">{{ $artikel->judul }}</h1>
{{-- Judul --}}
<h1 class="article-title mb-3">{{ $artikel->judul }}</h1>
<div class="flex items-center gap-4 text-xs text-gray-400 mb-6 pb-6 border-b border-gray-100">
<span>📅 {{ $artikel->published_at?->format('d M Y') ?? '-' }}</span>
@if($artikel->author)
<span>✍️ {{ $artikel->author->nama }}</span>
@endif
{{-- Meta --}}
<div class="article-meta flex items-center gap-5 mb-5">
<span>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5M1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4z"/>
</svg>
{{ $artikel->published_at?->format('d M Y') ?? '-' }}
</span>
<span>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
<path d="M1 2.828c.885-.37 2.154-.769 3.388-.893 1.33-.134 2.458.063 3.112.752v9.746c-.935-.53-2.12-.603-3.213-.493-1.18.12-2.37.461-3.287.811zm7.5-.141c.654-.689 1.782-.886 3.112-.752 1.234.124 2.503.523 3.388.893v9.923c-.918-.35-2.107-.692-3.287-.81-1.094-.111-2.278-.039-3.213.492zM8 1.783C7.015.936 5.587.81 4.287.94c-1.514.153-3.042.672-3.994 1.105A.5.5 0 0 0 0 2.5v11a.5.5 0 0 0 .707.455c.882-.4 2.303-.881 3.68-1.02 1.409-.142 2.59.087 3.223.877a.5.5 0 0 0 .78 0c.633-.79 1.814-1.019 3.222-.877 1.378.139 2.8.62 3.681 1.02A.5.5 0 0 0 16 13.5v-11a.5.5 0 0 0-.293-.455c-.952-.433-2.48-.952-3.994-1.105C10.413.809 8.985.936 8 1.783"/>
</svg>
{{ $artikel->subBab->count() }} sub-bab
</span>
</div>
{{-- Deskripsi --}}
@if($artikel->deskripsi_singkat)
<p class="text-gray-600 leading-relaxed mb-6 bg-green-50 rounded-xl p-4 italic border-l-4 border-green-400">
{{ $artikel->deskripsi_singkat }}
</p>
<p class="article-excerpt">{{ $artikel->deskripsi_singkat }}</p>
@endif
<div class="prose max-w-none text-gray-700 leading-relaxed text-sm">
{!! nl2br(e($artikel->konten)) !!}
</div>
</div>
</div>
<!-- Galeri -->
@if($artikel->galeri_gambar && count($artikel->galeri_gambar) > 0)
<div class="bg-white rounded-2xl shadow-lg p-6">
<h3 class="font-bold text-gray-800 mb-4 flex items-center">
<span class="w-8 h-8 bg-green-100 rounded-lg flex items-center justify-center mr-2 text-sm">🖼️</span>
Galeri Foto
</h3>
<div class="grid grid-cols-2 md:grid-cols-3 gap-3">
@foreach($artikel->galeri_gambar as $foto)
<img src="{{ Storage::url($foto) }}" class="w-full h-32 object-cover rounded-xl hover:opacity-90 transition cursor-pointer" alt="Galeri">
{{-- Sub-bab Accordion --}}
@if($artikel->subBab->count() > 0)
<div class="section-card">
<div class="section-header">
<div class="section-header-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#2e7d32" viewBox="0 0 16 16">
<path d="M5 10.5a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5m0-2a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5m0-2a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5m0-2a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5"/>
<path d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2m0 1a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1z"/>
</svg>
</div>
<h3>Isi Artikel</h3>
</div>
<div>
@foreach($artikel->subBab as $index => $sub)
<div class="accordion-item">
{{-- Trigger --}}
<button type="button" onclick="toggleAccordion({{ $index }})" class="accordion-trigger">
<span class="acc-num">{{ $index + 1 }}</span>
<span class="acc-title">{{ $sub->judul_sub }}</span>
<svg id="arrow-{{ $index }}" class="acc-arrow" 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>
</button>
{{-- Body --}}
<div id="accordion-{{ $index }}" class="accordion-body">
@if($sub->gambar)
<img src="{{ Storage::url($sub->gambar) }}" alt="{{ $sub->judul_sub }}">
@endif
@if($sub->konten)
<div class="konten-text">{{ $sub->konten }}</div>
@else
<p class="acc-empty">Konten belum tersedia.</p>
@endif
</div>
</div>
@endforeach
</div>
</div>
@else
<div class="empty-state">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="#9e9e9e" viewBox="0 0 16 16" style="margin:0 auto 12px;display:block;opacity:.6">
<path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1zm13 2.383-4.708 2.825L15 11.105zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741M1 11.105l4.708-2.897L1 5.383z"/>
</svg>
<p>Belum ada sub-bab</p>
</div>
@endif
</div>
<!-- Sidebar -->
<div class="space-y-6">
<!-- Info Artikel -->
<div class="bg-white rounded-2xl shadow-lg p-6">
<h3 class="font-bold text-gray-800 mb-4 flex items-center">
<span class="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center mr-2 text-sm"></span>
{{-- ══════════════════════════════════
SIDEBAR
══════════════════════════════════ --}}
<div class="space-y-5 sidebar-sticky">
{{-- Info Artikel --}}
<div class="sidebar-card">
<h3>
<span class="sidebar-icon" style="background:#e3f2fd">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="#1565c0" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
<path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
</svg>
</span>
Info Artikel
</h3>
<div class="space-y-3">
<div class="flex justify-between py-2 border-b border-gray-100">
<span class="text-xs text-gray-500">Kategori</span>
<span class="text-xs font-bold text-green-600">Budidaya</span>
<div class="info-row">
<span class="lbl">Kategori</span>
<span class="val green">Budidaya</span>
</div>
<div class="flex justify-between py-2 border-b border-gray-100">
<span class="text-xs text-gray-500">Tanggal</span>
<span class="text-xs font-semibold text-gray-800">{{ $artikel->published_at?->format('d M Y') ?? '-' }}</span>
</div>
@if($artikel->file_pdf)
<div class="pt-2">
<a href="{{ Storage::url($artikel->file_pdf) }}" target="_blank"
class="w-full flex items-center justify-center gap-2 px-4 py-3 bg-red-500 text-white font-bold rounded-xl hover:bg-red-600 transition text-sm">
📄 Download PDF
</a>
</div>
@endif
<div class="info-row">
<span class="lbl">Tanggal</span>
<span class="val">{{ $artikel->published_at?->format('d M Y') ?? '-' }}</span>
</div>
<div class="info-row">
<span class="lbl">Sub-bab</span>
<span class="val blue">{{ $artikel->subBab->count() }} sub-bab</span>
</div>
<!-- Tombol Aksi -->
<div class="bg-white rounded-2xl shadow-lg p-6 space-y-3">
<a href="{{ route('user.artikel.budidaya') }}"
class="w-full flex items-center justify-center gap-2 px-4 py-3 border-2 border-gray-200 text-gray-700 font-semibold rounded-xl hover:bg-gray-50 transition text-sm">
Kembali ke Daftar
@if($artikel->file_pdf)
<a href="{{ Storage::url($artikel->file_pdf) }}" target="_blank" class="btn-pdf">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">
<path d="M14 14V4.5L9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2M9.5 3A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h5.5z"/>
<path d="M4.603 14.087a.8.8 0 0 1-.438-.42c-.195-.388-.13-.776.08-1.102.198-.307.526-.568.897-.787a7.7 7.7 0 0 1 1.482-.645 20 20 0 0 0 1.062-2.227 7.3 7.3 0 0 1-.43-1.295c-.086-.4-.119-.796-.046-1.136.075-.354.274-.672.65-.823.192-.077.4-.12.602-.077a.7.7 0 0 1 .477.365c.088.164.12.356.127.538.007.188-.012.396-.047.614-.084.51-.27 1.134-.52 1.794a11 11 0 0 0 .98 1.686 5.8 5.8 0 0 1 1.334.05c.364.066.734.195.96.465.12.144.193.32.2.518.007.192-.047.382-.138.563a1.04 1.04 0 0 1-.354.416.86.86 0 0 1-.51.138c-.331-.014-.654-.196-.933-.417a5.7 5.7 0 0 1-.911-.95 11.7 11.7 0 0 0-1.997.406 11.3 11.3 0 0 1-1.02 1.51c-.292.35-.609.656-.927.787a.8.8 0 0 1-.58.029"/>
</svg>
Download PDF
</a>
<a href="{{ route('user.dashboard') }}"
class="w-full flex items-center justify-center gap-2 px-4 py-3 border-2 border-gray-200 text-gray-700 font-semibold rounded-xl hover:bg-gray-50 transition text-sm">
🏠 Dashboard
@endif
</div>
{{-- Navigasi --}}
<div class="sidebar-card space-y-3">
<a href="{{ route('user.artikel.budidaya') }}" class="btn-nav">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8"/>
</svg>
Kembali ke Daftar
</a>
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
function toggleAccordion(index) {
const content = document.getElementById(`accordion-${index}`);
const arrow = document.getElementById(`arrow-${index}`);
if (content.classList.contains('open')) {
content.classList.remove('open');
arrow.style.transform = 'rotate(0deg)';
} else {
content.classList.add('open');
arrow.style.transform = 'rotate(180deg)';
}
}
function bukaAccordion(index) {
const content = document.getElementById(`accordion-${index}`);
const arrow = document.getElementById(`arrow-${index}`);
content.classList.add('open');
arrow.style.transform = 'rotate(180deg)';
// Scroll ke accordion
content.closest('.accordion-item').scrollIntoView({ behavior: 'smooth', block: 'start' });
}
</script>
@endpush

View File

@ -1,142 +1,550 @@
@extends('layouts.user-app')
@section('page-title', '🦠 Artikel Hama & Penyakit')
@section('page-subtitle', '{{ $artikel->judul }}')
@section('page-title', 'Artikel Hama & Penyakit')
@section('page-subtitle', $artikel->judul)
@push('styles')
<style>
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400&family=DM+Sans:wght@300;400;500;600&display=swap');
.detail-hp { font-family: 'DM Sans', sans-serif; }
/* ── Hero Card ── */
.hero-card {
background: #fff;
border-radius: 24px;
box-shadow: 0 4px 24px rgba(0,0,0,.08);
overflow: hidden;
}
.hero-img-wrap {
position: relative;
height: 320px;
overflow: hidden;
}
.hero-img-wrap img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform .6s ease;
}
.hero-card:hover .hero-img-wrap img { transform: scale(1.03); }
.hero-img-overlay {
position: absolute;
inset: 0;
background: linear-gradient(to top, rgba(20,5,0,.5) 0%, transparent 55%);
}
.hero-placeholder {
width: 100%;
height: 280px;
display: flex;
align-items: center;
justify-content: center;
}
.hero-placeholder span {
font-size: 5rem;
filter: drop-shadow(0 4px 12px rgba(0,0,0,.2));
}
/* ── Badges & Tags ── */
.jenis-badge {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 5px 14px;
border-radius: 100px;
font-size: 11.5px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: .4px;
}
.badge-hama { background: #fff7ed; color: #c2410c; border: 1.5px solid #fdba74; }
.badge-penyakit { background: #fef2f2; color: #b91c1c; border: 1.5px solid #fca5a5; }
.tag-pill {
display: inline-flex;
align-items: center;
padding: 4px 12px;
border-radius: 100px;
font-size: 11px;
font-weight: 600;
background: #f3f4f6;
color: #374151;
border: 1.5px solid #e5e7eb;
}
/* ── Article Title ── */
.article-title {
font-family: 'Lora', serif;
font-size: 1.65rem;
font-weight: 700;
color: #1a0a00;
line-height: 1.35;
letter-spacing: -.3px;
}
.article-meta span {
font-size: 12px;
color: #9ca3af;
display: inline-flex;
align-items: center;
gap: 4px;
}
/* Excerpt */
.article-excerpt {
border-radius: 0 12px 12px 0;
padding: 16px 20px;
font-style: italic;
font-size: 13.5px;
line-height: 1.75;
border-left: 4px solid;
}
.excerpt-hama { background: linear-gradient(135deg,#fff7ed,#ffedd5); border-color: #f97316; color: #7c2d12; }
.excerpt-penyakit { background: linear-gradient(135deg,#fef2f2,#fee2e2); border-color: #ef4444; color: #7f1d1d; }
/* Main content */
.konten-text {
font-size: 14px;
color: #374151;
line-height: 1.85;
}
/* ── Info Teknis Grid ── */
.teknis-section {
border-top: 1px solid #f3f4f6;
padding-top: 28px;
margin-top: 8px;
}
.teknis-title {
font-family: 'Lora', serif;
font-weight: 600;
font-size: 1rem;
color: #1a0a00;
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 18px;
}
.teknis-icon {
width: 34px;
height: 34px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
flex-shrink: 0;
}
.teknis-grid {
display: grid;
grid-template-columns: 1fr;
gap: 14px;
}
@media (min-width: 768px) { .teknis-grid { grid-template-columns: repeat(2,1fr); } }
.teknis-card {
border-radius: 14px;
padding: 16px 18px;
border: 1.5px solid;
}
.teknis-card h4 {
font-weight: 700;
font-size: 12.5px;
margin-bottom: 8px;
display: flex;
align-items: center;
gap: 6px;
}
.teknis-card p {
font-size: 12.5px;
line-height: 1.7;
}
.tc-yellow { background: #fefce8; border-color: #fde68a; }
.tc-yellow h4 { color: #92400e; }
.tc-yellow p { color: #78350f; }
.tc-blue { background: #eff6ff; border-color: #bfdbfe; }
.tc-blue h4 { color: #1e40af; }
.tc-blue p { color: #1e3a8a; }
.tc-green { background: #f0fdf4; border-color: #bbf7d0; }
.tc-green h4 { color: #15803d; }
.tc-green p { color: #14532d; }
.tc-red { background: #fef2f2; border-color: #fecaca; }
.tc-red h4 { color: #b91c1c; }
.tc-red p { color: #7f1d1d; }
/* ── Galeri ── */
.galeri-card {
background: #fff;
border-radius: 24px;
box-shadow: 0 4px 24px rgba(0,0,0,.07);
padding: 24px 28px;
}
.galeri-title {
font-family: 'Lora', serif;
font-weight: 600;
font-size: 1rem;
color: #1a0a00;
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 18px;
}
.galeri-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
@media (min-width: 768px) { .galeri-grid { grid-template-columns: repeat(3, 1fr); } }
.galeri-grid img {
width: 100%;
height: 130px;
object-fit: cover;
border-radius: 12px;
transition: transform .3s ease, opacity .2s;
box-shadow: 0 2px 10px rgba(0,0,0,.07);
}
.galeri-grid img:hover { transform: scale(1.03); opacity: .9; }
/* ── Section Card (generic) ── */
.section-card {
background: #fff;
border-radius: 24px;
box-shadow: 0 4px 24px rgba(0,0,0,.07);
padding: 24px 28px;
}
/* ── Sidebar ── */
.sidebar-card {
background: #fff;
border-radius: 20px;
box-shadow: 0 4px 20px rgba(0,0,0,.07);
padding: 22px;
}
.sidebar-card h3 {
font-family: 'Lora', serif;
font-size: .95rem;
font-weight: 600;
color: #1a0a00;
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 16px;
}
.sidebar-icon {
width: 32px;
height: 32px;
border-radius: 9px;
display: flex;
align-items: center;
justify-content: center;
font-size: 15px;
flex-shrink: 0;
}
.info-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0;
border-bottom: 1px solid #f3f4f6;
font-size: 12.5px;
}
.info-row:last-of-type { border-bottom: none; }
.info-row .lbl { color: #9ca3af; }
.info-row .val { font-weight: 600; color: #111827; }
.val-hama { color: #c2410c !important; }
.val-penyakit { color: #b91c1c !important; }
.btn-pdf {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 12px 20px;
background: linear-gradient(135deg,#e53935,#b71c1c);
color: #fff;
font-weight: 600;
font-size: 13px;
border-radius: 12px;
text-decoration: none;
margin-top: 14px;
transition: opacity .2s, transform .15s;
box-shadow: 0 4px 12px rgba(183,28,28,.25);
}
.btn-pdf:hover { opacity: .9; transform: translateY(-1px); }
.btn-nav {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 12px 20px;
border: 2px solid #e5e7eb;
color: #374151;
font-weight: 600;
font-size: 13px;
border-radius: 12px;
text-decoration: none;
background: #fff;
transition: background .2s, border-color .2s, transform .15s;
}
.btn-nav:hover {
background: #f9fafb;
border-color: #d1d5db;
transform: translateY(-1px);
}
@media (min-width: 1024px) { .sidebar-sticky { position: sticky; top: 24px; } }
</style>
@endpush
@section('content')
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div class="detail-hp grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Konten Utama -->
{{-- ══════════════════════════════
KONTEN UTAMA
══════════════════════════════ --}}
<div class="lg:col-span-2 space-y-6">
<div class="bg-white rounded-2xl shadow-lg overflow-hidden">
{{-- Hero --}}
<div class="hero-card">
@if($artikel->gambar_utama)
<img src="{{ Storage::url($artikel->gambar_utama) }}" class="w-full h-64 object-cover" alt="{{ $artikel->judul }}">
<div class="hero-img-wrap">
<img src="{{ Storage::url($artikel->gambar_utama) }}" alt="{{ $artikel->judul }}">
<div class="hero-img-overlay"></div>
</div>
@else
<div class="w-full h-48 flex items-center justify-center {{ $artikel->jenis === 'Hama' ? 'bg-gradient-to-br from-orange-400 to-orange-600' : 'bg-gradient-to-br from-red-400 to-red-600' }}">
<span class="text-7xl">{{ $artikel->jenis === 'Hama' ? '🐛' : '🦠' }}</span>
<div class="hero-placeholder {{ $artikel->jenis === 'Hama' ? 'bg-gradient-to-br from-orange-300 to-orange-600' : 'bg-gradient-to-br from-red-300 to-red-700' }}">
@if($artikel->jenis === 'Hama')
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" fill="rgba(255,255,255,0.7)" viewBox="0 0 16 16">
<path d="M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71z"/>
<path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m7-8A7 7 0 1 1 1 8a7 7 0 0 1 14 0"/>
</svg>
@else
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" fill="rgba(255,255,255,0.7)" viewBox="0 0 16 16">
<path d="M6.5 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1zM11 7.5a4.002 4.002 0 0 1-3.512 3.96A1 1 0 0 1 7 12.5V14h1a.5.5 0 0 1 0 1H6a.5.5 0 0 1 0-1h.5V12.5a1 1 0 0 1-.988-.04A4.002 4.002 0 0 1 5 7.5H1.5a.5.5 0 0 1 0-1H5a4 4 0 0 1 6 0h3.5a.5.5 0 0 1 0 1z"/>
</svg>
@endif
</div>
@endif
<div class="p-8">
{{-- Badge jenis + tags --}}
<div class="flex flex-wrap gap-2 mb-4">
<span class="px-3 py-1 text-xs font-bold rounded-full {{ $artikel->jenis === 'Hama' ? 'bg-orange-100 text-orange-700' : 'bg-red-100 text-red-700' }}">
{{ $artikel->jenis === 'Hama' ? '🐛' : '🦠' }} {{ $artikel->jenis }}
<span class="jenis-badge {{ $artikel->jenis === 'Hama' ? 'badge-hama' : 'badge-penyakit' }}">
@if($artikel->jenis === 'Hama')
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
<path d="M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71z"/>
<path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m7-8A7 7 0 1 1 1 8a7 7 0 0 1 14 0"/>
</svg>
@else
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
<path d="M6.5 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1zM11 7.5a4.002 4.002 0 0 1-3.512 3.96A1 1 0 0 1 7 12.5V14h1a.5.5 0 0 1 0 1H6a.5.5 0 0 1 0-1h.5V12.5a1 1 0 0 1-.988-.04A4.002 4.002 0 0 1 5 7.5H1.5a.5.5 0 0 1 0-1H5a4 4 0 0 1 6 0h3.5a.5.5 0 0 1 0 1z"/>
</svg>
@endif
{{ $artikel->jenis }}
</span>
@if($artikel->tags)
@foreach($artikel->tags as $tag)
<span class="px-3 py-1 bg-gray-100 text-gray-600 text-xs font-semibold rounded-full">{{ $tag }}</span>
<span class="tag-pill">{{ $tag }}</span>
@endforeach
@endif
</div>
<h1 class="text-2xl font-bold text-gray-800 mb-2">{{ $artikel->judul }}</h1>
<div class="flex items-center gap-4 text-xs text-gray-400 mb-6 pb-6 border-b border-gray-100">
<span>📅 {{ $artikel->published_at?->format('d M Y') ?? '-' }}</span>
{{-- Judul --}}
<h1 class="article-title mb-3">{{ $artikel->judul }}</h1>
{{-- Meta --}}
<div class="flex items-center gap-5 mb-6 pb-6 border-b border-gray-100">
<span class="article-meta">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5M1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4z"/>
</svg>
{{ $artikel->published_at?->format('d M Y') ?? '-' }}
</span>
</div>
{{-- Excerpt --}}
@if($artikel->deskripsi_singkat)
<p class="text-gray-600 leading-relaxed mb-6 bg-gray-50 rounded-xl p-4 italic border-l-4 {{ $artikel->jenis === 'Hama' ? 'border-orange-400' : 'border-red-400' }}">
<p class="article-excerpt mb-6 {{ $artikel->jenis === 'Hama' ? 'excerpt-hama' : 'excerpt-penyakit' }}">
{{ $artikel->deskripsi_singkat }}
</p>
@endif
<div class="text-sm text-gray-700 leading-relaxed mb-6">
{{-- Konten utama --}}
<div class="konten-text mb-6">
{!! nl2br(e($artikel->konten)) !!}
</div>
<!-- Info Teknis -->
{{-- Info Teknis --}}
@if($artikel->gejala_visual || $artikel->cara_identifikasi || $artikel->pencegahan || $artikel->pengendalian)
<div class="border-t border-gray-100 pt-6">
<h3 class="font-bold text-gray-800 mb-4 flex items-center">
<span class="w-8 h-8 bg-red-100 rounded-lg flex items-center justify-center mr-2 text-sm">📋</span>
<div class="teknis-section">
<h3 class="teknis-title">
<span class="teknis-icon" style="background:#fef2f2">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#b91c1c" viewBox="0 0 16 16">
<path d="M5 10.5a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5m0-2a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5m0-2a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5m0-2a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5"/>
<path d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2m0 1a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1z"/>
</svg>
</span>
Informasi Teknis
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="teknis-grid">
@if($artikel->gejala_visual)
<div class="bg-yellow-50 border border-yellow-100 rounded-xl p-4">
<h4 class="font-bold text-yellow-700 text-sm mb-2">👁️ Gejala Visual</h4>
<p class="text-xs text-yellow-600 leading-relaxed">{{ $artikel->gejala_visual }}</p>
<div class="teknis-card tc-yellow">
<h4>
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" viewBox="0 0 16 16">
<path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8M1.173 8a13 13 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5s3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5s-3.879-1.168-5.168-2.457A13 13 0 0 1 1.172 8z"/>
<path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5M4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0"/>
</svg>
Gejala Visual
</h4>
<p>{{ $artikel->gejala_visual }}</p>
</div>
@endif
@if($artikel->cara_identifikasi)
<div class="bg-blue-50 border border-blue-100 rounded-xl p-4">
<h4 class="font-bold text-blue-700 text-sm mb-2">🔍 Cara Identifikasi</h4>
<p class="text-xs text-blue-600 leading-relaxed">{{ $artikel->cara_identifikasi }}</p>
<div class="teknis-card tc-blue">
<h4>
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" viewBox="0 0 16 16">
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.099zm-5.242 1.656a5.5 5.5 0 1 1 0-11 5.5 5.5 0 0 1 0 11"/>
</svg>
Cara Identifikasi
</h4>
<p>{{ $artikel->cara_identifikasi }}</p>
</div>
@endif
@if($artikel->pencegahan)
<div class="bg-green-50 border border-green-100 rounded-xl p-4">
<h4 class="font-bold text-green-700 text-sm mb-2">🛡️ Pencegahan</h4>
<p class="text-xs text-green-600 leading-relaxed">{{ $artikel->pencegahan }}</p>
<div class="teknis-card tc-green">
<h4>
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" viewBox="0 0 16 16">
<path d="M5.338 1.59a61 61 0 0 0-2.837.856.48.48 0 0 0-.328.39c-.554 4.157.726 7.19 2.253 9.188a10.7 10.7 0 0 0 2.287 2.233c.346.244.652.42.893.533q.18.085.293.118a1 1 0 0 0 .101.025 1 1 0 0 0 .1-.025q.114-.034.294-.118c.24-.113.547-.29.893-.533a10.7 10.7 0 0 0 2.287-2.233c1.527-1.997 2.807-5.031 2.253-9.188a.48.48 0 0 0-.328-.39c-.651-.213-1.75-.56-2.837-.855C9.552 1.29 8.531 1.067 8 1.067c-.53 0-1.552.223-2.662.524zM5.072.56C6.157.265 7.31 0 8 0s1.843.265 2.928.56c1.11.3 2.229.655 2.887.87a1.54 1.54 0 0 1 1.044 1.262c.596 4.477-.787 7.795-2.465 9.99a11.8 11.8 0 0 1-2.517 2.453 7 7 0 0 1-1.048.625c-.28.132-.581.24-.829.24s-.548-.108-.829-.24a7 7 0 0 1-1.048-.625 11.8 11.8 0 0 1-2.517-2.453C1.928 10.487.545 7.169 1.141 2.692A1.54 1.54 0 0 1 2.185 1.43 63 63 0 0 1 5.072.56"/>
</svg>
Pencegahan
</h4>
<p>{{ $artikel->pencegahan }}</p>
</div>
@endif
@if($artikel->pengendalian)
<div class="bg-red-50 border border-red-100 rounded-xl p-4">
<h4 class="font-bold text-red-700 text-sm mb-2">⚗️ Pengendalian</h4>
<p class="text-xs text-red-600 leading-relaxed">{{ $artikel->pengendalian }}</p>
<div class="teknis-card tc-red">
<h4>
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" viewBox="0 0 16 16">
<path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z"/>
</svg>
Pengendalian
</h4>
<p>{{ $artikel->pengendalian }}</p>
</div>
@endif
</div>
</div>
@endif
</div>
</div>
<!-- Galeri -->
{{-- Galeri --}}
@if($artikel->galeri_gambar && count($artikel->galeri_gambar) > 0)
<div class="bg-white rounded-2xl shadow-lg p-6">
<h3 class="font-bold text-gray-800 mb-4 flex items-center">
<span class="w-8 h-8 bg-gray-100 rounded-lg flex items-center justify-center mr-2 text-sm">🖼️</span>
<div class="galeri-card">
<h3 class="galeri-title">
<span class="teknis-icon" style="background:#f3f4f6">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#374151" viewBox="0 0 16 16">
<path d="M6.002 5.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0"/>
<path d="M1.5 2A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2zm13 1a.5.5 0 0 1 .5.5v6l-3.775-1.947a.5.5 0 0 0-.577.093l-3.71 3.71-2.66-1.772a.5.5 0 0 0-.63.062L1.002 12v.54L1 12.5v-9a.5.5 0 0 1 .5-.5z"/>
</svg>
</span>
Galeri Foto
</h3>
<div class="grid grid-cols-2 md:grid-cols-3 gap-3">
<div class="galeri-grid">
@foreach($artikel->galeri_gambar as $foto)
<img src="{{ Storage::url($foto) }}" class="w-full h-32 object-cover rounded-xl hover:opacity-90 transition" alt="Galeri">
<img src="{{ Storage::url($foto) }}" alt="Galeri">
@endforeach
</div>
</div>
@endif
</div>
<!-- Sidebar -->
<div class="space-y-6">
<div class="bg-white rounded-2xl shadow-lg p-6">
<h3 class="font-bold text-gray-800 mb-4 flex items-center">
<span class="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center mr-2 text-sm"></span>
{{-- ══════════════════════════════
SIDEBAR
══════════════════════════════ --}}
<div class="space-y-5 sidebar-sticky">
{{-- Info Artikel --}}
<div class="sidebar-card">
<h3>
<span class="sidebar-icon" style="background:#eff6ff">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="#1565c0" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
<path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
</svg>
</span>
Info Artikel
</h3>
<div class="space-y-3">
<div class="flex justify-between py-2 border-b border-gray-100">
<span class="text-xs text-gray-500">Jenis</span>
<span class="text-xs font-bold {{ $artikel->jenis === 'Hama' ? 'text-orange-600' : 'text-red-600' }}">{{ $artikel->jenis }}</span>
</div>
<div class="flex justify-between py-2 border-b border-gray-100">
<span class="text-xs text-gray-500">Tanggal</span>
<span class="text-xs font-semibold text-gray-800">{{ $artikel->published_at?->format('d M Y') ?? '-' }}</span>
</div>
@if($artikel->file_pdf)
<div class="pt-2">
<a href="{{ Storage::url($artikel->file_pdf) }}" target="_blank"
class="w-full flex items-center justify-center gap-2 px-4 py-3 bg-red-500 text-white font-bold rounded-xl hover:bg-red-600 transition text-sm">
📄 Download PDF
</a>
</div>
@endif
<div class="info-row">
<span class="lbl">Jenis</span>
<span class="val {{ $artikel->jenis === 'Hama' ? 'val-hama' : 'val-penyakit' }}">{{ $artikel->jenis }}</span>
</div>
<div class="info-row">
<span class="lbl">Tanggal</span>
<span class="val">{{ $artikel->published_at?->format('d M Y') ?? '-' }}</span>
</div>
<div class="bg-white rounded-2xl shadow-lg p-6 space-y-3">
<a href="{{ route('user.artikel.hama-penyakit') }}"
class="w-full flex items-center justify-center gap-2 px-4 py-3 border-2 border-gray-200 text-gray-700 font-semibold rounded-xl hover:bg-gray-50 transition text-sm">
Kembali ke Daftar
@if($artikel->file_pdf)
<a href="{{ Storage::url($artikel->file_pdf) }}" target="_blank" class="btn-pdf">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">
<path d="M14 14V4.5L9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2M9.5 3A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h5.5z"/>
<path d="M4.603 14.087a.8.8 0 0 1-.438-.42c-.195-.388-.13-.776.08-1.102.198-.307.526-.568.897-.787a7.7 7.7 0 0 1 1.482-.645 20 20 0 0 0 1.062-2.227 7.3 7.3 0 0 1-.43-1.295c-.086-.4-.119-.796-.046-1.136.075-.354.274-.672.65-.823.192-.077.4-.12.602-.077a.7.7 0 0 1 .477.365c.088.164.12.356.127.538.007.188-.012.396-.047.614-.084.51-.27 1.134-.52 1.794a11 11 0 0 0 .98 1.686 5.8 5.8 0 0 1 1.334.05c.364.066.734.195.96.465.12.144.193.32.2.518.007.192-.047.382-.138.563a1.04 1.04 0 0 1-.354.416.86.86 0 0 1-.51.138c-.331-.014-.654-.196-.933-.417a5.7 5.7 0 0 1-.911-.95 11.7 11.7 0 0 0-1.997.406 11.3 11.3 0 0 1-1.02 1.51c-.292.35-.609.656-.927.787a.8.8 0 0 1-.58.029"/>
</svg>
Download PDF
</a>
<a href="{{ route('user.dashboard') }}"
class="w-full flex items-center justify-center gap-2 px-4 py-3 border-2 border-gray-200 text-gray-700 font-semibold rounded-xl hover:bg-gray-50 transition text-sm">
🏠 Dashboard
@endif
</div>
{{-- Navigasi --}}
<div class="sidebar-card space-y-3">
<a href="{{ route('user.artikel.hama-penyakit') }}" class="btn-nav">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8"/>
</svg>
Kembali ke Daftar
</a>
</div>
</div>
</div>
@endsection

View File

@ -1,122 +1,390 @@
@extends('layouts.user-app')
@section('page-title', '🦠 Artikel Hama & Penyakit')
@section('page-title', 'Artikel Hama & Penyakit')
@section('page-subtitle', 'Informasi seputar hama dan penyakit tanaman kopi')
@section('content')
<!-- Tab -->
<div class="bg-white rounded-2xl shadow-lg p-2 mb-6 flex gap-2">
<button onclick="switchTab('hama')" id="tab-hama"
class="flex-1 py-3 px-4 rounded-xl font-bold text-sm transition tab-btn active-tab">
🐛 Hama ({{ $hama->count() }})
</button>
<button onclick="switchTab('penyakit')" id="tab-penyakit"
class="flex-1 py-3 px-4 rounded-xl font-bold text-sm transition tab-btn">
🦠 Penyakit ({{ $penyakit->count() }})
</button>
</div>
<!-- Hama -->
<div id="content-hama">
@if($hama->count() > 0)
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
@foreach($hama as $artikel)
<a href="{{ route('user.artikel.hama-penyakit.detail', $artikel->slug) }}"
class="bg-white rounded-2xl shadow-lg overflow-hidden hover:shadow-xl transition-all hover:-translate-y-1 group">
<div class="h-48 bg-gradient-to-br from-orange-400 to-orange-600 overflow-hidden relative">
@if($artikel->gambar_utama)
<img src="{{ Storage::url($artikel->gambar_utama) }}" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" alt="{{ $artikel->judul }}">
@else
<div class="w-full h-full flex items-center justify-center">
<span class="text-6xl">🐛</span>
</div>
@endif
<span class="absolute top-3 right-3 px-2 py-1 bg-orange-500 text-white text-xs font-bold rounded-full">Hama</span>
</div>
<div class="p-5">
@if($artikel->tags)
<div class="flex flex-wrap gap-1 mb-3">
@foreach(array_slice($artikel->tags, 0, 2) as $tag)
<span class="px-2 py-0.5 bg-orange-100 text-orange-700 text-xs font-semibold rounded-full">{{ $tag }}</span>
@endforeach
</div>
@endif
<h3 class="font-bold text-gray-800 mb-2 group-hover:text-orange-600 transition-colors line-clamp-2">{{ $artikel->judul }}</h3>
@if($artikel->deskripsi_singkat)
<p class="text-xs text-gray-500 leading-relaxed line-clamp-3 mb-4">{{ $artikel->deskripsi_singkat }}</p>
@endif
<div class="flex items-center justify-between pt-3 border-t border-gray-100">
<span class="text-xs text-gray-400">{{ $artikel->published_at?->format('d M Y') ?? '-' }}</span>
<span class="text-xs font-semibold text-orange-600 group-hover:underline">Baca </span>
</div>
</div>
</a>
@endforeach
</div>
@else
<div class="bg-white rounded-2xl shadow-lg p-16 text-center text-gray-400">
<span class="text-6xl block mb-4">🐛</span>
<p class="text-xl font-semibold">Belum ada artikel hama</p>
</div>
@endif
</div>
<!-- Penyakit -->
<div id="content-penyakit" class="hidden">
@if($penyakit->count() > 0)
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
@foreach($penyakit as $artikel)
<a href="{{ route('user.artikel.hama-penyakit.detail', $artikel->slug) }}"
class="bg-white rounded-2xl shadow-lg overflow-hidden hover:shadow-xl transition-all hover:-translate-y-1 group">
<div class="h-48 bg-gradient-to-br from-red-400 to-red-600 overflow-hidden relative">
@if($artikel->gambar_utama)
<img src="{{ Storage::url($artikel->gambar_utama) }}" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" alt="{{ $artikel->judul }}">
@else
<div class="w-full h-full flex items-center justify-center">
<span class="text-6xl">🦠</span>
</div>
@endif
<span class="absolute top-3 right-3 px-2 py-1 bg-red-500 text-white text-xs font-bold rounded-full">Penyakit</span>
</div>
<div class="p-5">
@if($artikel->tags)
<div class="flex flex-wrap gap-1 mb-3">
@foreach(array_slice($artikel->tags, 0, 2) as $tag)
<span class="px-2 py-0.5 bg-red-100 text-red-700 text-xs font-semibold rounded-full">{{ $tag }}</span>
@endforeach
</div>
@endif
<h3 class="font-bold text-gray-800 mb-2 group-hover:text-red-600 transition-colors line-clamp-2">{{ $artikel->judul }}</h3>
@if($artikel->deskripsi_singkat)
<p class="text-xs text-gray-500 leading-relaxed line-clamp-3 mb-4">{{ $artikel->deskripsi_singkat }}</p>
@endif
<div class="flex items-center justify-between pt-3 border-t border-gray-100">
<span class="text-xs text-gray-400">{{ $artikel->published_at?->format('d M Y') ?? '-' }}</span>
<span class="text-xs font-semibold text-red-600 group-hover:underline">Baca </span>
</div>
</div>
</a>
@endforeach
</div>
@else
<div class="bg-white rounded-2xl shadow-lg p-16 text-center text-gray-400">
<span class="text-6xl block mb-4">🦠</span>
<p class="text-xl font-semibold">Belum ada artikel penyakit</p>
</div>
@endif
</div>
@endsection
@push('styles')
<style>
.active-tab { background: #16a34a; color: white; }
.tab-btn:not(.active-tab) { color: #6b7280; }
.tab-btn:not(.active-tab):hover { background: #f3f4f6; }
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400&family=DM+Sans:wght@300;400;500;600&display=swap');
.hp-page { font-family: 'DM Sans', sans-serif; }
/* ── Tab Switcher ── */
.tab-wrap {
background: #fff;
border-radius: 20px;
box-shadow: 0 4px 20px rgba(0,0,0,.07);
padding: 8px;
display: flex;
gap: 8px;
margin-bottom: 28px;
}
.tab-btn {
flex: 1;
padding: 13px 20px;
border-radius: 14px;
border: none;
font-family: 'DM Sans', sans-serif;
font-weight: 600;
font-size: 13.5px;
cursor: pointer;
transition: background .22s, color .22s, box-shadow .22s, transform .15s;
color: #6b7280;
background: transparent;
}
.tab-btn:hover:not(.active-tab) {
background: #f9fafb;
color: #374151;
}
/* Hama active */
#tab-hama.active-tab {
background: linear-gradient(135deg, #f97316, #ea580c);
color: #fff;
box-shadow: 0 6px 20px rgba(234,88,12,.28);
transform: translateY(-1px);
}
/* Penyakit active */
#tab-penyakit.active-tab {
background: linear-gradient(135deg, #ef4444, #b91c1c);
color: #fff;
box-shadow: 0 6px 20px rgba(185,28,28,.28);
transform: translateY(-1px);
}
/* ── Grid ── */
.artikel-grid {
display: grid;
grid-template-columns: 1fr;
gap: 24px;
}
@media (min-width: 768px) { .artikel-grid { grid-template-columns: repeat(2,1fr); } }
@media (min-width: 1024px) { .artikel-grid { grid-template-columns: repeat(3,1fr); } }
/* ── Card ── */
.artikel-card {
background: #fff;
border-radius: 20px;
box-shadow: 0 4px 20px rgba(0,0,0,.07);
overflow: hidden;
display: flex;
flex-direction: column;
text-decoration: none;
border: 1.5px solid #f5f5f5;
transition: transform .25s ease, box-shadow .25s ease, border-color .25s;
}
.artikel-card.hama:hover { transform: translateY(-6px); box-shadow: 0 16px 40px rgba(234,88,12,.13); border-color: #fed7aa; }
.artikel-card.penyakit:hover { transform: translateY(-6px); box-shadow: 0 16px 40px rgba(185,28,28,.13); border-color: #fecaca; }
/* Image */
.card-img-wrap {
height: 200px;
overflow: hidden;
position: relative;
}
.card-img-wrap img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform .45s ease;
}
.artikel-card:hover .card-img-wrap img { transform: scale(1.07); }
.card-img-overlay {
position: absolute;
inset: 0;
background: linear-gradient(to top, rgba(20,10,0,.45) 0%, transparent 55%);
}
.card-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.card-placeholder span {
font-size: 4rem;
filter: drop-shadow(0 4px 8px rgba(0,0,0,.15));
}
/* Badge */
.card-badge {
position: absolute;
top: 12px;
right: 12px;
padding: 4px 12px;
border-radius: 100px;
font-size: 10.5px;
font-weight: 700;
letter-spacing: .4px;
text-transform: uppercase;
backdrop-filter: blur(6px);
}
.badge-hama { background: rgba(234,88,12,.85); color: #fff; }
.badge-penyakit { background: rgba(185,28,28,.85); color: #fff; }
/* Body */
.card-body {
padding: 18px 20px 20px;
flex: 1;
display: flex;
flex-direction: column;
}
/* Tags */
.card-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 11px; }
.card-tag {
padding: 3px 10px;
border-radius: 100px;
font-size: 10.5px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: .3px;
border: 1px solid;
}
.tag-hama { background: #fff7ed; color: #c2410c; border-color: #fdba74; }
.tag-penyakit { background: #fef2f2; color: #b91c1c; border-color: #fca5a5; }
/* Title */
.card-title {
font-family: 'Lora', serif;
font-weight: 700;
font-size: .98rem;
line-height: 1.4;
margin-bottom: 9px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
transition: color .2s;
}
.card-title.hama { color: #1c0a00; }
.card-title.penyakit { color: #1c0000; }
.artikel-card.hama:hover .card-title { color: #c2410c; }
.artikel-card.penyakit:hover .card-title { color: #b91c1c; }
/* Excerpt */
.card-excerpt {
font-size: 12.5px;
color: #6b7280;
line-height: 1.75;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
flex: 1;
margin-bottom: 14px;
}
/* Footer */
.card-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 12px;
border-top: 1px solid #f5f5f5;
margin-top: auto;
}
.card-date { font-size: 11.5px; color: #9ca3af; }
.card-cta {
font-size: 12px;
font-weight: 700;
padding: 6px 14px;
border-radius: 100px;
transition: background .2s, color .2s;
}
.cta-hama { color: #c2410c; background: #fff7ed; }
.cta-penyakit { color: #b91c1c; background: #fef2f2; }
.artikel-card.hama:hover .card-cta { background: #ea580c; color: #fff; }
.artikel-card.penyakit:hover .card-cta { background: #ef4444; color: #fff; }
/* ── Empty State ── */
.empty-state {
background: #fff;
border-radius: 24px;
box-shadow: 0 4px 20px rgba(0,0,0,.07);
padding: 80px 24px;
text-align: center;
}
.empty-state .empty-icon { font-size: 3.5rem; display: block; margin-bottom: 14px; opacity: .5; }
.empty-state h3 {
font-family: 'Lora', serif;
font-size: 1.2rem;
font-weight: 700;
color: #374151;
margin-bottom: 4px;
}
.empty-state p { font-size: 13px; color: #9ca3af; }
/* ── Tab content transition ── */
.tab-content { animation: fadeIn .25s ease; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
</style>
@endpush
@section('content')
<div class="hp-page">
{{-- ── Tab Switcher ── --}}
<div class="tab-wrap">
<button onclick="switchTab('hama')" id="tab-hama" class="tab-btn active-tab">
Hama
<span style="opacity:.75;font-weight:400;font-size:12px">({{ $hama->count() }})</span>
</button>
<button onclick="switchTab('penyakit')" id="tab-penyakit" class="tab-btn">
Penyakit
<span style="opacity:.75;font-weight:400;font-size:12px">({{ $penyakit->count() }})</span>
</button>
</div>
{{-- ── Konten Hama ── --}}
<div id="content-hama" class="tab-content">
@if($hama->count() > 0)
<div class="artikel-grid">
@foreach($hama as $artikel)
<a href="{{ route('user.artikel.hama-penyakit.detail', $artikel->slug) }}" class="artikel-card hama">
<div class="card-img-wrap" style="background: linear-gradient(135deg,#fdba74,#ea580c)">
@if($artikel->gambar_utama)
<img src="{{ Storage::url($artikel->gambar_utama) }}" alt="{{ $artikel->judul }}">
<div class="card-img-overlay"></div>
@else
<div class="card-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" fill="rgba(255,255,255,0.6)" viewBox="0 0 16 16">
<path d="M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71z"/>
<path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m7-8A7 7 0 1 1 1 8a7 7 0 0 1 14 0"/>
</svg>
</div>
@endif
<span class="card-badge badge-hama">Hama</span>
</div>
<div class="card-body">
@if($artikel->tags)
<div class="card-tags">
@foreach(array_slice($artikel->tags, 0, 2) as $tag)
<span class="card-tag tag-hama">{{ $tag }}</span>
@endforeach
</div>
@endif
<h3 class="card-title hama">{{ $artikel->judul }}</h3>
@if($artikel->deskripsi_singkat)
<p class="card-excerpt">{{ $artikel->deskripsi_singkat }}</p>
@endif
<div class="card-footer">
<span class="card-date" style="display:flex;align-items:center;gap:4px">
<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" fill="currentColor" viewBox="0 0 16 16">
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5M1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4z"/>
</svg>
{{ $artikel->published_at?->format('d M Y') ?? '-' }}
</span>
<span class="card-cta cta-hama">Baca &rarr;</span>
</div>
</div>
</a>
@endforeach
</div>
@else
<div class="empty-state">
<svg xmlns="http://www.w3.org/2000/svg" width="52" height="52" fill="#9ca3af" viewBox="0 0 16 16" style="margin:0 auto 14px;display:block;opacity:.5">
<path d="M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71z"/>
<path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m7-8A7 7 0 1 1 1 8a7 7 0 0 1 14 0"/>
</svg>
<h3>Belum ada artikel hama</h3>
<p>Artikel akan segera tersedia</p>
</div>
@endif
</div>
{{-- ── Konten Penyakit ── --}}
<div id="content-penyakit" class="tab-content hidden">
@if($penyakit->count() > 0)
<div class="artikel-grid">
@foreach($penyakit as $artikel)
<a href="{{ route('user.artikel.hama-penyakit.detail', $artikel->slug) }}" class="artikel-card penyakit">
<div class="card-img-wrap" style="background: linear-gradient(135deg,#fca5a5,#b91c1c)">
@if($artikel->gambar_utama)
<img src="{{ Storage::url($artikel->gambar_utama) }}" alt="{{ $artikel->judul }}">
<div class="card-img-overlay"></div>
@else
<div class="card-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" fill="rgba(255,255,255,0.6)" viewBox="0 0 16 16">
<path d="M6.5 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1zM11 7.5a4.002 4.002 0 0 1-3.512 3.96A1 1 0 0 1 7 12.5V14h1a.5.5 0 0 1 0 1H6a.5.5 0 0 1 0-1h.5V12.5a1 1 0 0 1-.988-.04A4.002 4.002 0 0 1 5 7.5H1.5a.5.5 0 0 1 0-1H5a4 4 0 0 1 6 0h3.5a.5.5 0 0 1 0 1z"/>
</svg>
</div>
@endif
<span class="card-badge badge-penyakit">Penyakit</span>
</div>
<div class="card-body">
@if($artikel->tags)
<div class="card-tags">
@foreach(array_slice($artikel->tags, 0, 2) as $tag)
<span class="card-tag tag-penyakit">{{ $tag }}</span>
@endforeach
</div>
@endif
<h3 class="card-title penyakit">{{ $artikel->judul }}</h3>
@if($artikel->deskripsi_singkat)
<p class="card-excerpt">{{ $artikel->deskripsi_singkat }}</p>
@endif
<div class="card-footer">
<span class="card-date" style="display:flex;align-items:center;gap:4px">
<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" fill="currentColor" viewBox="0 0 16 16">
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5M1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4z"/>
</svg>
{{ $artikel->published_at?->format('d M Y') ?? '-' }}
</span>
<span class="card-cta cta-penyakit">Baca &rarr;</span>
</div>
</div>
</a>
@endforeach
</div>
@else
<div class="empty-state">
<svg xmlns="http://www.w3.org/2000/svg" width="52" height="52" fill="#9ca3af" viewBox="0 0 16 16" style="margin:0 auto 14px;display:block;opacity:.5">
<path d="M6.5 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1zM11 7.5a4.002 4.002 0 0 1-3.512 3.96A1 1 0 0 1 7 12.5V14h1a.5.5 0 0 1 0 1H6a.5.5 0 0 1 0-1h.5V12.5a1 1 0 0 1-.988-.04A4.002 4.002 0 0 1 5 7.5H1.5a.5.5 0 0 1 0-1H5a4 4 0 0 1 6 0h3.5a.5.5 0 0 1 0 1z"/>
</svg>
<h3>Belum ada artikel penyakit</h3>
<p>Artikel akan segera tersedia</p>
</div>
@endif
</div>
</div>
@endsection
@push('scripts')
<script>
function switchTab(tab) {