<!doctype html>

<html lang="en">

<head>

  <meta charset="utf-8" />

  <meta name="viewport" content="width=device-width, initial-scale=1" />

  <title>NewsAPI → RSS Controller</title>

  <script src="https://cdn.tailwindcss.com"></script>

  <link rel="preconnect" href="https://fonts.googleapis.com">

  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">

  <style>

    body { font-family: Inter, ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji"; }

    .card { @apply rounded-2xl shadow-sm border border-slate-200 bg-white; }

    .label { @apply block text-sm font-semibold text-slate-700 mb-1; }

    .input { @apply w-full rounded-xl border border-slate-300 px-3 py-2 outline-none focus:ring-2 focus:ring-indigo-500; }

    .select { @apply w-full rounded-xl border border-slate-300 px-3 py-2 outline-none focus:ring-2 focus:ring-indigo-500 bg-white; }

    .btn { @apply inline-flex items-center gap-2 rounded-xl bg-indigo-600 text-white px-4 py-2 font-semibold hover:bg-indigo-700 active:bg-indigo-800 disabled:opacity-50; }

    .btn-secondary { @apply inline-flex items-center gap-2 rounded-xl bg-slate-200 text-slate-800 px-3 py-2 font-semibold hover:bg-slate-300; }

    .pill { @apply inline-flex items-center gap-2 rounded-full bg-slate-100 px-3 py-1 text-sm text-slate-700; }

    code.url { @apply break-all text-sm text-indigo-700; }

  </style>

</head>

<body class="min-h-screen bg-slate-50">

  <main class="max-w-5xl mx-auto p-6 space-y-6">

    <header class="flex items-center justify-between">

      <h1 class="text-2xl font-bold text-slate-900">NewsAPI → RSS Controller</h1>

      <a class="pill" target="_blank" href="https://newsapi.org/">Powered by NewsAPI</a>

    </header>


    <section class="card p-5">

      <div class="grid md:grid-cols-2 gap-4">

        <div>

          <label class="label">Worker Base URL</label>

          <input id="baseUrl" class="input" placeholder="https://YOUR-SUBDOMAIN.workers.dev" />

          <p class="text-xs text-slate-500 mt-1">Example: <span class="text-slate-700">https://lingering-voice-be3f.abhijit-acharya.workers.dev</span></p>

        </div>

        <div>

          <label class="label">Mode</label>

          <div class="flex gap-4 mt-2">

            <label class="inline-flex items-center gap-2"><input type="radio" name="mode" value="top" class="accent-indigo-600" checked> <span>Top Headlines</span></label>

            <label class="inline-flex items-center gap-2"><input type="radio" name="mode" value="search" class="accent-indigo-600"> <span>Keyword Search</span></label>

          </div>

        </div>

      </div>


      <div class="grid md:grid-cols-3 gap-4 mt-4" id="topFields">

        <div>

          <label class="label">Country</label>

          <select id="country" class="select">

            <option value="">— any —</option>

            <option value="in">India</option>

            <option value="us">United States</option>

            <option value="gb">United Kingdom</option>

            <option value="au">Australia</option>

            <option value="ca">Canada</option>

            <option value="de">Germany</option>

            <option value="fr">France</option>

            <option value="jp">Japan</option>

            <option value="sg">Singapore</option>

          </select>

        </div>

        <div>

          <label class="label">Category</label>

          <select id="category" class="select">

            <option value="">— any —</option>

            <option>business</option>

            <option>entertainment</option>

            <option>general</option>

            <option>health</option>

            <option>science</option>

            <option>sports</option>

            <option>technology</option>

          </select>

        </div>

        <div>

          <label class="label">Page Size (1–50)</label>

          <input id="pageSize" type="number" min="1" max="50" value="5" class="input" />

        </div>

      </div>


      <div class="grid md:grid-cols-3 gap-4 mt-4 hidden" id="searchFields">

        <div class="md:col-span-2">

          <label class="label">Keyword (q)</label>

          <input id="q" class="input" placeholder="e.g. ai india, crypto, climate" />

        </div>

        <div>

          <label class="label">Language</label>

          <select id="language" class="select">

            <option>en</option>

            <option>hi</option>

            <option>de</option>

            <option>fr</option>

            <option>es</option>

            <option>it</option>

            <option>ja</option>

            <option>ru</option>

            <option>zh</option>

          </select>

        </div>

      </div>


      <div class="flex flex-wrap items-center gap-3 mt-6">

        <button id="build" class="btn">Build RSS URL</button>

        <button id="copy" class="btn-secondary">Copy URL</button>

        <a id="open" class="btn" target="_blank" href="#">Open in new tab</a>

        <span id="status" class="text-sm text-slate-500"></span>

      </div>


      <div class="mt-4 p-3 bg-slate-50 rounded-xl border border-slate-200">

        <div class="text-xs uppercase tracking-wide text-slate-500">RSS URL</div>

        <code id="urlOut" class="url"></code>

      </div>

    </section>


    <section class="card p-5">

      <div class="flex items-center justify-between">

        <h2 class="text-lg font-semibold">Preview (first 10 items)</h2>

        <button id="previewBtn" class="btn-secondary">Refresh Preview</button>

      </div>

      <ol id="preview" class="mt-4 space-y-3 list-decimal list-inside"></ol>

    </section>


    <footer class="text-center text-xs text-slate-500 py-6">Client-side UI only. Your Worker does the heavy lifting.</footer>

  </main>


  <script>

    const els = {

      baseUrl: document.getElementById('baseUrl'),

      mode: () => document.querySelector('input[name="mode"]:checked')?.value,

      topFields: document.getElementById('topFields'),

      searchFields: document.getElementById('searchFields'),

      country: document.getElementById('country'),

      category: document.getElementById('category'),

      pageSize: document.getElementById('pageSize'),

      q: document.getElementById('q'),

      language: document.getElementById('language'),

      build: document.getElementById('build'),

      copy: document.getElementById('copy'),

      open: document.getElementById('open'),

      urlOut: document.getElementById('urlOut'),

      status: document.getElementById('status'),

      previewBtn: document.getElementById('previewBtn'),

      preview: document.getElementById('preview'),

    };


    // Prefill base URL if we know it

    const saved = JSON.parse(localStorage.getItem('newsui') || '{}');

    if (saved.baseUrl) els.baseUrl.value = saved.baseUrl;

    if (saved.country) els.country.value = saved.country;

    if (saved.category) els.category.value = saved.category;

    if (saved.pageSize) els.pageSize.value = saved.pageSize;

    if (saved.mode) document.querySelector(`input[name="mode"][value="${saved.mode}"]`)?.click();

    if (saved.q) els.q.value = saved.q;

    if (saved.language) els.language.value = saved.language;


    function saveState() {

      localStorage.setItem('newsui', JSON.stringify({

        baseUrl: els.baseUrl.value.trim(),

        country: els.country.value,

        category: els.category.value,

        pageSize: els.pageSize.value,

        mode: els.mode(),

        q: els.q.value,

        language: els.language.value,

      }));

    }


    function toggleModeUI() {

      const m = els.mode();

      if (m === 'top') { els.topFields.classList.remove('hidden'); els.searchFields.classList.add('hidden'); }

      else { els.topFields.classList.add('hidden'); els.searchFields.classList.remove('hidden'); }

    }


    document.querySelectorAll('input[name="mode"]').forEach(r => r.addEventListener('change', () => { toggleModeUI(); buildUrl(); saveState(); }));

    [els.baseUrl, els.country, els.category, els.pageSize, els.q, els.language].forEach(el => el.addEventListener('input', () => { buildUrl(); saveState(); }));


    function buildUrl() {

      const base = els.baseUrl.value.trim().replace(/\/$/, '');

      if (!base) { els.urlOut.textContent = ''; return ''; }

      const m = els.mode();

      const ps = Math.max(1, Math.min(parseInt(els.pageSize.value || '5', 10), 50));

      let url = base + '/rss?';

      if (m === 'top') {

        const params = new URLSearchParams();

        if (els.country.value) params.set('country', els.country.value);

        if (els.category.value) params.set('category', els.category.value);

        params.set('pageSize', String(ps));

        url += params.toString();

      } else {

        const q = els.q.value.trim();

        const params = new URLSearchParams();

        if (q) params.set('q', q);

        params.set('language', els.language.value);

        params.set('pageSize', String(ps));

        url += params.toString();

      }

      els.urlOut.textContent = url;

      els.open.href = url;

      return url;

    }


    async function preview() {

      els.status.textContent = 'Fetching…';

      els.preview.innerHTML = '';

      const url = buildUrl();

      if (!url) { els.status.textContent = 'Enter your Worker base URL first.'; return; }

      try {

        const res = await fetch(url, { headers: { 'Accept': 'application/rss+xml' } });

        if (!res.ok) throw new Error('HTTP ' + res.status);

        const text = await res.text();

        const doc = new window.DOMParser().parseFromString(text, 'application/xml');

        const items = Array.from(doc.querySelectorAll('item')).slice(0, 10);

        if (items.length === 0) {

          els.status.textContent = 'No items in feed (try another combo or keyword).';

          return;

        }

        const frag = document.createDocumentFragment();

        items.forEach((it, i) => {

          const li = document.createElement('li');

          const title = it.querySelector('title')?.textContent || '(no title)';

          const link = it.querySelector('link')?.textContent || '#';

          li.innerHTML = `<a class="text-indigo-700 hover:underline" target="_blank" href="${link}">${title}</a>`;

          frag.appendChild(li);

        });

        els.preview.appendChild(frag);

        els.status.textContent = '';

      } catch (err) {

        els.status.textContent = 'Preview failed: ' + (err.message || err);

      }

    }


    els.build.addEventListener('click', (e) => { e.preventDefault(); buildUrl(); });

    els.copy.addEventListener('click', async (e) => {

      e.preventDefault();

      const url = buildUrl();

      if (!url) return;

      try { await navigator.clipboard.writeText(url); els.status.textContent = 'Copied!'; setTimeout(() => els.status.textContent = '', 1500); } catch {}

    });

    els.previewBtn.addEventListener('click', (e) => { e.preventDefault(); preview(); });


    // Initial paint

    toggleModeUI();

    buildUrl();

  </script>

</body>

</html>