<div id="unduhan-ppg">
  <div class="dl-wrap">
    <div class="dl-head">
      <h2 class="dl-title">Unduhan PPG</h2>
      <div class="dl-tools">
        <input class="dl-search" id="dlSearch" type="search" placeholder="Cari file..." autocomplete="off" />
        <button class="dl-btn dl-btn--all" id="dlBtnAll" type="button" aria-pressed="true">Semua</button>
        <button class="dl-btn dl-btn--reset" id="dlBtnReset" type="button">Reset</button>
      </div>
    </div>

    <div class="dl-tools" id="dlKinds" style="gap:8px"></div>

    <div class="dl-table-wrap" role="region" aria-label="Tabel unduhan" tabindex="0">
      <table class="dl-table" aria-describedby="dlPagerInfo">
        <thead>
          <tr>
            <th style="min-width:260px">File</th>
            <th style="width:180px">Jenis</th>
            <th style="width:160px">Tanggal</th>
            <th style="width:220px;text-align:right">Aksi</th>
          </tr>
        </thead>
        <tbody id="dlTbody"></tbody>
      </table>
    </div>

    <div class="dl-pager" id="dlPager">
      <div class="dl-page-info" id="dlPagerInfo">Memuat...</div>
      <div class="dl-pagination">
        <button class="dl-page-btn dl-page-btn--prev" id="dlPrev" type="button" disabled>Prev</button>
        <div class="dl-page-numbers" id="dlPageNumbers"></div>
        <button class="dl-page-btn dl-page-btn--next" id="dlNext" type="button" disabled>Next</button>
      </div>
    </div>
  </div>
</div>

<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700;800&display=swap');

#unduhan-ppg{
  --c-cyan:#2ec0ee; --c-blue:#429cef; --c-indigo:#597cf0;
  --c-sky:#91c2f6;  --c-surf:#bddcf8;
  --ink:#0f172a;    --muted:#54607b;
  --ring:color-mix(in oklab, var(--c-indigo) 35%, transparent);

  --ico-eye: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 5c-6 0-10 7-10 7s4 7 10 7 10-7 10-7-4-7-10-7Zm0 12a5 5 0 1 1 0-10 5 5 0 0 1 0 10Zm0-2.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5Z'/%3E%3C/svg%3E");
  --ico-download: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3a1 1 0 0 1 1 1v9.59l2.3-2.3a1 1 0 1 1 1.4 1.42l-4 4a1 1 0 0 1-1.4 0l-4-4a1 1 0 1 1 1.4-1.42L11 13.59V4a1 1 0 0 1 1-1Zm-7 16a1 1 0 0 1 1-1h12a1 1 0 1 1 0 2H6a1 1 0 0 1-1-1Z'/%3E%3C/svg%3E");
  --ico-filter: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 6a1 1 0 1 1 0-2h16a1 1 0 1 1 0 2H4Zm3 7a1 1 0 0 1 0-2h10a1 1 0 1 1 0 2H7Zm3 7a1 1 0 0 1 0-2h4a1 1 0 1 1 0 2h-4Z'/%3E%3C/svg%3E");
  --ico-grid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 4h7v7H4V4Zm9 0h7v7h-7V4ZM4 13h7v7H4v-7Zm9 0h7v7h-7v-7Z'/%3E%3C/svg%3E");
  --ico-reset: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 6a6 6 0 1 1-5.65 8H4a1 1 0 1 1 0-2h3.5a1 1 0 0 1 .96.72A4 4 0 1 0 12 8h-1.17l.88.88a1 1 0 0 1-1.42 1.42l-2.6-2.6a1 1 0 0 1 0-1.42l2.6-2.6a1 1 0 0 1 1.42 1.42L10.83 6H12Z'/%3E%3C/svg%3E");
  --ico-left: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M14.7 6.3a1 1 0 0 1 0 1.4L10.4 12l4.3 4.3a1 1 0 1 1-1.4 1.4l-5-5a1 1 0 0 1 0-1.4l5-5a1 1 0 0 1 1.4 0Z'/%3E%3C/svg%3E");
  --ico-right: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9.3 17.7a1 1 0 0 1 0-1.4L13.6 12 9.3 7.7a1 1 0 1 1 1.4-1.4l5 5a1 1 0 0 1 0 1.4l-5 5a1 1 0 0 1-1.4 0Z'/%3E%3C/svg%3E");

  padding:clamp(28px,6vw,64px) clamp(18px,5vw,56px);
  margin-top:clamp(16px,4vw,48px);
  border-radius:24px;
  background:
    radial-gradient(900px 420px at 100% 0%, color-mix(in oklab, var(--c-sky) 18%, transparent), transparent 60%),
    linear-gradient(180deg, #ffffff, color-mix(in oklab, var(--c-surf) 18%, #fff) 120%);
  color:var(--ink);
  box-shadow:0 12px 36px rgba(0,0,0,.04);
}

#unduhan-ppg, #unduhan-ppg *{
  font-family:"Poppins",system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;
  box-sizing:border-box;
}

.dl-wrap{max-width:1100px;margin-inline:auto;display:grid;gap:18px}
.dl-head{display:flex;gap:14px;align-items:center;justify-content:space-between;flex-wrap:wrap}

.dl-title{
  font:800 clamp(22px,3.6vw,36px)/1.15 "Poppins",system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;
  margin:0;
  color:transparent;
  background:linear-gradient(90deg,var(--c-blue),var(--c-indigo));
  -webkit-background-clip:text;
  background-clip:text;
  position:relative;
}
.dl-title::after{
  content:"";
  position:absolute;
  left:0;
  bottom:-8px;
  width:120px;
  height:3px;
  border-radius:999px;
  background:linear-gradient(90deg,var(--c-cyan),var(--c-indigo));
}

.dl-tools{display:flex;gap:10px;align-items:center;flex-wrap:wrap}

.dl-search{
  height:42px;
  min-width:240px;
  padding:0 14px 0 38px;
  border-radius:999px;
  border:1px solid rgba(2,6,23,.08);
  background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24'%3E%3Cpath fill='%2354607b' d='M10 4a6 6 0 1 1-4.24 10.24l-2.52 2.52l-1.48-1.48l2.52-2.52A6 6 0 0 1 10 4m0 2a4 4 0 1 0 0 8a4 4 0 0 0 0-8'/%3E%3C/svg%3E") no-repeat 12px center/18px 18px;
  outline:none;
  color:var(--ink);
  box-shadow:0 6px 18px rgba(0,0,0,.03);
}
.dl-search:focus{box-shadow:0 0 0 8px var(--ring)}

.dl-btn,
.dl-view,
.dl-download{
  display:inline-flex;
  align-items:center;
  gap:8px;
  -webkit-tap-highlight-color:transparent;
}

.dl-btn::before,
.dl-view::before,
.dl-download::before{
  content:"";
  width:18px;
  height:18px;
  flex:0 0 18px;
  display:inline-block;
  background:currentColor;
  -webkit-mask:no-repeat center/18px 18px;
  mask:no-repeat center/18px 18px;
  opacity:.95;
}

.dl-btn{
  height:42px;
  padding:0 16px;
  border-radius:999px;
  border:1px solid rgba(2,6,23,.08);
  background:#fff;
  color:var(--ink);
  font-weight:700;
  cursor:pointer;
  user-select:none;
  transition:transform .15s ease, background-color .15s ease, border-color .15s ease;
}
.dl-btn:hover{
  transform:translateY(-1px);
  border-color:color-mix(in oklab, var(--c-indigo) 30%, #fff);
  background:color-mix(in oklab, var(--c-surf) 18%, #fff);
}
.dl-btn:focus-visible{outline:0;box-shadow:0 0 0 8px var(--ring)}
.dl-btn[aria-pressed="true"]{
  border-color:color-mix(in oklab, var(--c-indigo) 55%, #fff);
  background:linear-gradient(90deg,color-mix(in oklab, var(--c-cyan) 14%, #fff),color-mix(in oklab, var(--c-indigo) 12%, #fff));
}

.dl-btn--all::before{ -webkit-mask-image:var(--ico-grid); mask-image:var(--ico-grid); }
.dl-btn--reset::before{ -webkit-mask-image:var(--ico-reset); mask-image:var(--ico-reset); }
.dl-btn--kind::before{ -webkit-mask-image:var(--ico-filter); mask-image:var(--ico-filter); }

.dl-table-wrap{
  overflow:auto;
  border-radius:16px;
  box-shadow:0 10px 28px color-mix(in oklab, var(--c-indigo) 20%, transparent);
  border:1px solid rgba(2,6,23,.06);
  background:#fff;
}

table.dl-table{width:100%;border-collapse:separate;border-spacing:0}
.dl-table thead th{
  text-align:left;
  font-weight:800;
  font-size:14px;
  letter-spacing:.02em;
  color:#19304f;
  background:linear-gradient(90deg,color-mix(in oklab, var(--c-surf) 72%, #fff),#fff);
  position:sticky;
  top:0;
  z-index:1;
  padding:14px 16px;
  border-bottom:1px solid rgba(2,6,23,.06);
}
.dl-table tbody td{
  padding:14px 16px;
  border-bottom:1px solid rgba(2,6,23,.05);
  color:#1f2937;
  vertical-align:middle;
}
.dl-table tbody tr:hover{background:color-mix(in oklab, var(--c-surf) 10%, #fff)}

.dl-file{display:flex;align-items:center;gap:12px;min-width:220px}
.dl-file .dl-icon{
  width:36px;
  height:36px;
  border-radius:10px;
  display:grid;
  place-items:center;
  background:linear-gradient(90deg,var(--c-cyan),var(--c-indigo));
  color:#fff;
  box-shadow:0 8px 22px color-mix(in oklab, var(--c-indigo) 40%, transparent);
  flex:0 0 auto;
  font-weight:900;
  font-size:11px;
  letter-spacing:.06em;
}
.dl-file .dl-name{font-weight:800}
.dl-file .dl-desc{font-size:12px;color:var(--muted);margin-top:2px}

.dl-chip{
  display:inline-flex;
  align-items:center;
  gap:6px;
  font-size:12px;
  padding:4px 10px;
  border-radius:999px;
  background:color-mix(in oklab, var(--c-surf) 65%, #fff);
  color:#19304f;
  font-weight:700;
  border:1px solid rgba(2,6,23,.06);
  white-space:nowrap;
}

.dl-actions{display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end}

.dl-view{
  height:38px;
  padding:0 14px;
  border-radius:999px;
  text-decoration:none;
  font-weight:700;
  background:#fff;
  color:var(--c-indigo);
  border:1px solid color-mix(in oklab, var(--c-indigo) 60%, #fff);
  box-shadow:0 4px 12px rgba(15,23,42,.06);
  transition:transform .18s ease, background-color .18s ease, color .18s ease, border-color .18s ease;
}
.dl-view::before{
  background:currentColor;
  -webkit-mask-image:var(--ico-eye);
  mask-image:var(--ico-eye);
}
.dl-view:hover{
  transform:translateY(-1px);
  background:color-mix(in oklab, var(--c-surf) 45%, #fff);
  border-color:var(--c-indigo);
}
.dl-view:focus-visible{outline:0;box-shadow:0 0 0 8px var(--ring)}

.dl-download{
  height:38px;
  padding:0 14px;
  border-radius:999px;
  text-decoration:none;
  font-weight:800;
  color:#fff;
  position:relative;
  overflow:hidden;
  background:linear-gradient(90deg,var(--c-cyan),var(--c-indigo));
  box-shadow:0 10px 28px color-mix(in oklab, var(--c-indigo) 40%, transparent);
  transition:transform .18s ease, filter .18s ease;
}
.dl-download::before{
  background:#fff;
  -webkit-mask-image:var(--ico-download);
  mask-image:var(--ico-download);
}
.dl-download::after{
  content:"";
  position:absolute;
  inset:0;
  background:linear-gradient(100deg,transparent 10%,rgba(255,255,255,.55) 50%,transparent 90%);
  transform:translateX(-120%);
  animation:dl-sheen 3s ease-in-out infinite;
}
.dl-download:hover{transform:translateY(-1px);filter:saturate(1.05)}
.dl-download:focus-visible{outline:0;box-shadow:0 0 0 8px var(--ring)}

@keyframes dl-sheen{
  10%{transform:translateX(-120%)}
  45%{transform:translateX(120%)}
  100%{transform:translateX(120%)}
}

.dl-pager{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:12px;
  flex-wrap:wrap;
  padding:4px 2px 0;
}
.dl-page-info{font-size:12.5px;color:var(--muted);font-weight:600}

.dl-pagination{display:flex;align-items:center;gap:6px}
.dl-page-btn{
  height:34px;
  min-width:34px;
  padding:0 10px;
  border-radius:10px;
  border:1px solid rgba(2,6,23,.08);
  background:#fff;
  font-weight:800;
  color:#0f172a;
  cursor:pointer;
  box-shadow:0 4px 10px rgba(0,0,0,.04);
  transition:transform .15s ease, border-color .15s ease, background-color .15s ease;
}
.dl-page-btn:hover{
  transform:translateY(-1px);
  border-color:color-mix(in oklab, var(--c-indigo) 40%, #fff);
  background:color-mix(in oklab, var(--c-surf) 40%, #fff);
}
.dl-page-btn:focus-visible{outline:0;box-shadow:0 0 0 6px var(--ring)}
.dl-page-btn[disabled]{opacity:.45;cursor:not-allowed;transform:none}

.dl-page-btn--prev,
.dl-page-btn--next{display:inline-flex;align-items:center;gap:6px}

.dl-page-btn--prev::before,
.dl-page-btn--next::before{
  content:"";
  width:16px;height:16px;flex:0 0 16px;
  background:currentColor;
  -webkit-mask:no-repeat center/16px 16px;
  mask:no-repeat center/16px 16px;
}
.dl-page-btn--prev::before{ -webkit-mask-image:var(--ico-left); mask-image:var(--ico-left); }
.dl-page-btn--next::before{ -webkit-mask-image:var(--ico-right); mask-image:var(--ico-right); }

.dl-page-numbers{display:flex;align-items:center;gap:6px}
.dl-page-number{height:34px;min-width:34px;padding:0 10px}
.dl-page-number[aria-current="page"]{
  background:linear-gradient(90deg,color-mix(in oklab, var(--c-cyan) 25%, #fff),color-mix(in oklab, var(--c-indigo) 22%, #fff));
  border-color:color-mix(in oklab, var(--c-indigo) 55%, #fff);
  color:#0b1b3a;
}

@media (max-width:780px){
  .dl-table thead{display:none}
  .dl-table,.dl-table tbody,.dl-table tr,.dl-table td{display:block;width:100%}
  .dl-table tbody tr{padding:14px 12px}
  .dl-table tbody td{border:0;padding:8px 0}
  .dl-actions{margin-top:8px;justify-content:flex-start}
  .dl-pager{align-items:flex-start}
}

@media (prefers-reduced-motion:reduce){
  .dl-download::after{animation:none!important}
}
</style>

<script>
(function(){
  const root = document.getElementById('unduhan-ppg');
  if(!root) return;

  const $ = (s, el=root) => el.querySelector(s);
  const $$ = (s, el=root) => Array.from(el.querySelectorAll(s));

  const elSearch = $('#dlSearch');
  const elKinds = $('#dlKinds');
  const elTbody = $('#dlTbody');
  const elInfo = $('#dlPagerInfo');
  const elPrev = $('#dlPrev');
  const elNext = $('#dlNext');
  const elNums = $('#dlPageNumbers');
  const btnAll = $('#dlBtnAll');
  const btnReset = $('#dlBtnReset');

  const ajaxUrl = (window.PPG_DOWNLOADS && window.PPG_DOWNLOADS.ajaxUrl) ? window.PPG_DOWNLOADS.ajaxUrl : '/wp-admin/admin-ajax.php';

  const state = { q:'', kind:'', page:1, perPage:10, total:0, kinds:[] };
  let lastReq = 0;

  function esc(s){
    return String(s ?? '').replace(/[&<>"']/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m]));
  }

  function getExtLabel(item){
    const ext = (item.ext || item.file_ext || '').toString().trim().toUpperCase();
    if(ext) return ext.slice(0,4);
    const url = (item.download_url || item.url || '').toString();
    const m = url.match(/\.([a-z0-9]{2,6})(?:\?|#|$)/i);
    return m ? m[1].toUpperCase().slice(0,4) : 'FILE';
  }

  function setPressedAll(){
    btnAll.setAttribute('aria-pressed', state.kind ? 'false' : 'true');
  }

  function renderKinds(){
    const kinds = state.kinds && state.kinds.length ? state.kinds : [];
    if(!kinds.length){
      elKinds.innerHTML = '';
      return;
    }
    const parts = kinds.map(k => {
      const active = (state.kind === k.slug);
      return `<button class="dl-btn dl-btn--kind" type="button" data-kind="${esc(k.slug)}" aria-pressed="${active?'true':'false'}">${esc(k.name)}</button>`;
    });
    elKinds.innerHTML = parts.join('');
    $$('.dl-btn--kind', elKinds).forEach(b=>{
      b.addEventListener('click', ()=>{
        state.kind = b.getAttribute('data-kind') || '';
        state.page = 1;
        setPressedAll();
        $$('.dl-btn--kind', elKinds).forEach(x=>x.setAttribute('aria-pressed','false'));
        b.setAttribute('aria-pressed','true');
        load();
      });
    });
  }

  function renderRows(items){
    if(!items || !items.length){
      elTbody.innerHTML = `<tr><td colspan="4" style="padding:18px 16px;color:var(--muted);font-weight:700">Tidak ada data.</td></tr>`;
      return;
    }
    elTbody.innerHTML = items.map(it=>{
      const title = it.title || it.name || 'Untitled';
      const desc = it.desc || it.description || '';
      const kind = (it.kind_name || it.kind || it.category || '-') + '';
      const date = (it.date || it.created_at || it.updated_at || '-') + '';
      const view = it.view_url || it.preview_url || it.url || '#';
      const dl = it.download_url || it.file_url || it.url || '#';
      const ext = getExtLabel(it);

      return `
        <tr>
          <td>
            <div class="dl-file">
              <div class="dl-icon">${esc(ext)}</div>
              <div>
                <div class="dl-name">${esc(title)}</div>
                ${desc ? `<div class="dl-desc">${esc(desc)}</div>` : ``}
              </div>
            </div>
          </td>
          <td><span class="dl-chip">${esc(kind)}</span></td>
          <td>${esc(date)}</td>
          <td>
            <div class="dl-actions">
              <a class="dl-view" href="${esc(view)}" target="_blank" rel="noopener">Lihat</a>
              <a class="dl-download" href="${esc(dl)}" download>Unduh</a>
            </div>
          </td>
        </tr>
      `;
    }).join('');
  }

  function renderPager(){
    const totalPages = Math.max(1, Math.ceil(state.total / state.perPage));
    const page = Math.min(state.page, totalPages);

    const from = state.total ? ((page - 1) * state.perPage + 1) : 0;
    const to = state.total ? Math.min(page * state.perPage, state.total) : 0;

    elInfo.textContent = state.total
      ? `Menampilkan ${from}–${to} dari ${state.total} file`
      : `Menampilkan 0 file`;

    elPrev.disabled = page <= 1;
    elNext.disabled = page >= totalPages;

    const windowSize = 5;
    let start = Math.max(1, page - Math.floor(windowSize/2));
    let end = Math.min(totalPages, start + windowSize - 1);
    start = Math.max(1, end - windowSize + 1);

    const nums = [];
    for(let i=start;i<=end;i++){
      nums.push(`<button class="dl-page-btn dl-page-number" type="button" data-page="${i}" ${i===page?'aria-current="page"':''}>${i}</button>`);
    }
    elNums.innerHTML = nums.join('');

    $$('.dl-page-number', elNums).forEach(b=>{
      b.addEventListener('click', ()=>{
        const p = parseInt(b.getAttribute('data-page') || '1', 10);
        state.page = isNaN(p) ? 1 : p;
        load();
      });
    });

    elPrev.onclick = ()=>{
      if(state.page>1){ state.page--; load(); }
    };
    elNext.onclick = ()=>{
      if(state.page<totalPages){ state.page++; load(); }
    };
  }

  async function fetchJSON(body){
    const res = await fetch(ajaxUrl, {
      method:'POST',
      headers:{'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'},
      body: new URLSearchParams(body).toString()
    });
    const txt = await res.text();
    try { return JSON.parse(txt); } catch(e){ return { success:false, data:null, raw:txt }; }
  }

  async function load(){
    const reqId = ++lastReq;

    elTbody.innerHTML = `<tr><td colspan="4" style="padding:18px 16px;color:var(--muted);font-weight:700">Memuat...</td></tr>`;
    elInfo.textContent = 'Memuat...';

    const payload = {
      action:'ppg_get_downloads',
      s: state.q,
      kind: state.kind,
      page: String(state.page),
      per_page: String(state.perPage)
    };

    const json = await fetchJSON(payload);
    if(reqId !== lastReq) return;

    const data = (json && typeof json === 'object')
      ? (json.success && json.data ? json.data : json.data || json)
      : null;

    const items = data && (data.items || data.results || data.downloads) ? (data.items || data.results || data.downloads) : [];
    state.total = Number(data && (data.total || data.total_items || data.count) ? (data.total || data.total_items || data.count) : items.length) || 0;

    const kinds = data && (data.kinds || data.categories || data.kind_list) ? (data.kinds || data.categories || data.kind_list) : null;
    if(Array.isArray(kinds)) state.kinds = kinds.map(k=>{
      if(typeof k === 'string') return { slug:k, name:k };
      return { slug:(k.slug || k.id || k.term_id || k.name || '').toString(), name:(k.name || k.slug || '').toString() };
    }).filter(x=>x.slug && x.name);

    renderKinds();
    renderRows(items);
    renderPager();
    setPressedAll();
  }

  function debounce(fn, wait){
    let t;
    return function(){
      clearTimeout(t);
      const args = arguments;
      t = setTimeout(()=>fn.apply(null,args), wait);
    };
  }

  elSearch.addEventListener('input', debounce(()=>{
    state.q = elSearch.value.trim();
    state.page = 1;
    load();
  }, 250));

  btnAll.addEventListener('click', ()=>{
    state.kind = '';
    state.page = 1;
    setPressedAll();
    $$('.dl-btn--kind', elKinds).forEach(x=>x.setAttribute('aria-pressed','false'));
    load();
  });

  btnReset.addEventListener('click', ()=>{
    state.q = '';
    state.kind = '';
    state.page = 1;
    elSearch.value = '';
    setPressedAll();
    $$('.dl-btn--kind', elKinds).forEach(x=>x.setAttribute('aria-pressed','false'));
    load();
  });

  load();
})();
</script>