Files
lpj/resources/views/daftar-pustaka/show.blade.php
Daeng Deni Mardaeni 3ce84b89b4 feat(daftar-pustaka): implementasi fitur Daftar Pustaka dengan peningkatan UI/UX & breadcrumb navigation
## 📋 Ringkasan
Implementasi penuh fitur Daftar Pustaka dengan peningkatan UI/UX, dukungan gesture swipe di PDF viewer mobile, serta integrasi breadcrumb untuk navigasi yang lebih intuitif.

## 🔄 Perubahan Utama
- app/Services/DaftarPustakaService.php
  • Refactor method getDaftarPustaka(), hapus handleUpload_()
  • Optimasi filtering & perbaiki format kode

- resources/views/daftar-pustaka/create.blade.php
  • Aktifkan breadcrumb navigation dengan {{ Breadcrumbs::render() }}

- resources/views/daftar-pustaka/index.blade.php
  • Konsolidasi class CSS, perbaikan flex & pagination styling

- resources/views/daftar-pustaka/show.blade.php
  • Tambah gesture swipe (touchstart, touchend) untuk PDF viewer
  • Implementasi handleSwipe() & threshold swipe 50px

- routes/breadcrumbs.php
  • Tambah route breadcrumbs daftar-pustaka (index, show, create)
2025-11-10 09:11:48 +07:00

167 lines
6.3 KiB
PHP

@extends('layouts.main')
@section('breadcrumbs')
{{ Breadcrumbs::render(request()->route()->getName(), $daftarPustaka) }}
@endsection
@section('content')
<div class="grid gap-5 mx-auto w-full lg:gap-7.5">
<form
action="{{ isset($daftarPustaka->id) ? route('daftar-pustaka.update', $daftarPustaka->id) : route('daftar-pustaka.store') }}"
method="POST">
@csrf
<div class="pb-2.5 border card border-agi-100">
<div class="card-header bg-agi-50" id="basic_settings">
<h3 class="card-title">
{{ $daftarPustaka->judul ?? '' }}
</h3>
<div class="flex gap-2 items-center">
<a href="{{ route('daftar-pustaka.index') }}" class="btn btn-xs btn-info">
<i class="ki-filled ki-exit-left"></i> Back
</a>
</div>
</div>
<div class="grid gap-5 card-body">
<div class="min-w-3xl">
<div class="flex flex-col p-4 h-full">
<div class="flex justify-between items-center mb-4">
<a href="{{ asset('storage/' . $daftarPustaka->attachment) }}" class="btn btn-primary btn-sm">
<i class="ki-duotone ki-cloud-download me-1"></i>
Download File
</a>
</div>
@php
$fileExtension = pathinfo($daftarPustaka->attachment, PATHINFO_EXTENSION);
$isPdf = strtolower($fileExtension) == 'pdf';
$imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
$isImage = in_array(strtolower($fileExtension), $imageExtensions);
$fileUrl = asset('storage/' . $daftarPustaka->attachment);
@endphp
@if ($isPdf)
<canvas id="pdfViewer" class="w-full rounded border touch-pan-y"></canvas>
<div class="flex gap-3 justify-center mt-3">
<button type="button" id="prevPage" class="btn btn-primary btn-sm">Previous</button>
<span>Page: <span id="pageNum">1</span> / <span id="pageCount">0</span></span>
<button type="button" id="nextPage" class="btn btn-primary btn-sm">Next</button>
</div>
@elseif ($isImage)
<img src="{{ $fileUrl }}" class="object-contain w-full rounded" />
@else
<p class="text-red-500">File tidak bisa ditampilkan, silakan
<a href="{{ $fileUrl }}" class="text-blue-500 underline" download>unduh di sini</a>.
</p>
@endif
</div>
</div>
<div class="border border-t"></div>
<div>
{{ $daftarPustaka->deskripsi ?? '' }}
</div>
</div>
</div>
</form>
</div>
@endsection
@push('scripts')
<!-- PDF.js CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
const url = @json($fileUrl);
if (url.endsWith('.pdf')) {
const pdfjsLib = window['pdfjs-dist/build/pdf'];
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
let pdfDoc = null;
let pageNum = 1;
let pageRendering = false;
let pageNumPending = null;
const scale = 1.3;
const canvas = document.getElementById('pdfViewer');
const ctx = canvas.getContext('2d');
function renderPage(num) {
pageRendering = true;
pdfDoc.getPage(num).then(function (page) {
const viewport = page.getViewport({ scale: scale });
canvas.height = viewport.height;
canvas.width = viewport.width;
const renderContext = {
canvasContext: ctx,
viewport: viewport
};
const renderTask = page.render(renderContext);
renderTask.promise.then(function () {
pageRendering = false;
document.getElementById('pageNum').textContent = num;
if (pageNumPending !== null) {
renderPage(pageNumPending);
pageNumPending = null;
}
});
});
}
function queueRenderPage(num) {
if (pageRendering) {
pageNumPending = num;
} else {
renderPage(num);
}
}
function onPrevPage() {
if (pageNum <= 1) return;
pageNum--;
queueRenderPage(pageNum);
}
function onNextPage() {
if (pageNum >= pdfDoc.numPages) return;
pageNum++;
queueRenderPage(pageNum);
}
document.getElementById('prevPage').addEventListener('click', onPrevPage);
document.getElementById('nextPage').addEventListener('click', onNextPage);
// Swipe gesture
let touchStartX = 0;
let touchEndX = 0;
canvas.addEventListener('touchstart', function (e) {
touchStartX = e.changedTouches[0].screenX;
});
canvas.addEventListener('touchend', function (e) {
touchEndX = e.changedTouches[0].screenX;
handleSwipe();
});
function handleSwipe() {
const swipeThreshold = 50; // min distance for swipe
if (touchEndX < touchStartX - swipeThreshold) {
onNextPage();
} else if (touchEndX > touchStartX + swipeThreshold) {
onPrevPage();
}
}
pdfjsLib.getDocument(url).promise.then(function (pdfDoc_) {
pdfDoc = pdfDoc_;
document.getElementById('pageCount').textContent = pdfDoc.numPages;
renderPage(pageNum);
});
}
});
</script>
@endpush