| --- |
| layout: null |
| title: Pashto Resource Search |
| description: Search verified Pashto (Pukhto/Pashto) datasets, models, tools, benchmarks, papers, and projects. |
| permalink: /search/ |
| --- |
| <!doctype html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| <title>Pashto Resource Search</title> |
| <meta name="description" content="Search verified Pashto (Pukhto/Pashto) resources for ASR, TTS, NLP, machine translation, tools, datasets, models, and benchmarks."> |
| <meta name="keywords" content="Pashto resources, Pukhto resources, Pashto datasets, Pashto ASR, Pashto TTS, Pashto NLP, Pashto machine translation, Pashto benchmarks"> |
| <meta name="robots" content="index,follow,max-image-preview:large"> |
| <link rel="canonical" href="https://musawer1214.github.io/pashto-language-resources/search/"> |
| <meta property="og:type" content="website"> |
| <meta property="og:site_name" content="Pashto Language Resources Hub"> |
| <meta property="og:title" content="Pashto Resource Search"> |
| <meta property="og:description" content="Discover verified Pashto datasets, models, tools, benchmarks, projects, and papers."> |
| <meta property="og:url" content="https://musawer1214.github.io/pashto-language-resources/search/"> |
| <meta name="twitter:card" content="summary"> |
| <meta name="twitter:title" content="Pashto Resource Search"> |
| <meta name="twitter:description" content="Search and filter verified Pashto language technology resources."> |
| <script type="application/ld+json"> |
| { |
| "@context": "https://schema.org", |
| "@type": "CollectionPage", |
| "name": "Pashto Resource Search", |
| "url": "https://musawer1214.github.io/pashto-language-resources/search/", |
| "description": "Search verified and candidate Pashto resources for ASR, TTS, NLP, MT, tools, datasets, and benchmarks.", |
| "inLanguage": "en", |
| "about": [ |
| "Pashto datasets", |
| "Pashto ASR", |
| "Pashto TTS", |
| "Pashto NLP", |
| "Pashto machine translation" |
| ] |
| } |
| </script> |
| <link rel="preconnect" href="https://fonts.googleapis.com"> |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
| <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Arabic:wght@400;500;700&family=Space+Grotesk:wght@500;700&display=swap" rel="stylesheet"> |
| <style> |
| :root { |
| --bg: #f6f4ec; |
| --panel: #fffef9; |
| --ink: #1d2a24; |
| --muted: #4c6158; |
| --line: #d6ddd7; |
| --brand: #106b53; |
| --brand-soft: #e0f0ea; |
| --accent: #c76a1a; |
| --accent-soft: #f7e9d8; |
| --shadow: 0 12px 30px rgba(29, 42, 36, 0.08); |
| } |
| |
| * { box-sizing: border-box; } |
| |
| body { |
| margin: 0; |
| font-family: "IBM Plex Sans Arabic", "Segoe UI", sans-serif; |
| color: var(--ink); |
| background: |
| radial-gradient(circle at 8% 12%, #fce4c4 0, rgba(252, 228, 196, 0) 35%), |
| radial-gradient(circle at 92% 6%, #d8ece5 0, rgba(216, 236, 229, 0) 38%), |
| var(--bg); |
| min-height: 100vh; |
| } |
| |
| .wrap { |
| max-width: 1100px; |
| margin: 0 auto; |
| padding: 24px 18px 44px; |
| } |
| |
| .hero { |
| background: linear-gradient(120deg, #fff, #f7fbf9); |
| border: 1px solid var(--line); |
| box-shadow: var(--shadow); |
| border-radius: 18px; |
| padding: 20px 18px; |
| margin-bottom: 16px; |
| transform: translateY(8px); |
| opacity: 0; |
| animation: rise 500ms ease forwards; |
| } |
| |
| .eyebrow { |
| letter-spacing: 0.07em; |
| text-transform: uppercase; |
| color: var(--accent); |
| font-family: "Space Grotesk", sans-serif; |
| font-weight: 700; |
| font-size: 12px; |
| margin-bottom: 6px; |
| } |
| |
| h1 { |
| margin: 0 0 8px; |
| font-family: "Space Grotesk", sans-serif; |
| font-size: 33px; |
| line-height: 1.1; |
| } |
| |
| .hero p { |
| margin: 0; |
| color: var(--muted); |
| line-height: 1.5; |
| } |
| |
| .controls { |
| margin-top: 14px; |
| display: grid; |
| grid-template-columns: 2.2fr 1fr 1fr 1fr 1fr; |
| gap: 10px; |
| } |
| |
| .field { |
| display: flex; |
| flex-direction: column; |
| gap: 5px; |
| } |
| |
| .field label { |
| font-size: 12px; |
| font-weight: 700; |
| color: var(--muted); |
| letter-spacing: 0.04em; |
| text-transform: uppercase; |
| font-family: "Space Grotesk", sans-serif; |
| } |
| |
| input, select { |
| width: 100%; |
| border: 1px solid var(--line); |
| background: var(--panel); |
| color: var(--ink); |
| border-radius: 10px; |
| padding: 10px 11px; |
| font: inherit; |
| } |
| |
| input:focus, select:focus { |
| outline: 2px solid #8cc9b5; |
| border-color: #8cc9b5; |
| } |
| |
| .summary { |
| margin: 14px 2px 6px; |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| gap: 12px; |
| color: var(--muted); |
| font-size: 14px; |
| } |
| |
| .badge { |
| background: var(--brand-soft); |
| color: var(--brand); |
| border: 1px solid #b7dccc; |
| padding: 3px 9px; |
| border-radius: 999px; |
| font-weight: 600; |
| } |
| |
| .crawl { |
| margin: 8px 2px 16px; |
| color: var(--muted); |
| font-size: 14px; |
| line-height: 1.5; |
| } |
| |
| .crawl p { |
| margin: 6px 0; |
| } |
| |
| .crawl-links { |
| margin: 8px 0 0; |
| padding-left: 18px; |
| } |
| |
| .crawl-links li { |
| margin: 3px 0; |
| } |
| |
| .grid { |
| display: grid; |
| grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); |
| gap: 12px; |
| list-style: none; |
| padding: 0; |
| margin: 0; |
| } |
| |
| .card { |
| border: 1px solid var(--line); |
| border-radius: 14px; |
| background: var(--panel); |
| box-shadow: var(--shadow); |
| padding: 13px 12px; |
| display: flex; |
| flex-direction: column; |
| gap: 9px; |
| opacity: 0; |
| animation: rise 420ms ease forwards; |
| } |
| |
| .chips { |
| display: flex; |
| gap: 6px; |
| flex-wrap: wrap; |
| } |
| |
| .chip { |
| border-radius: 999px; |
| padding: 2px 8px; |
| font-size: 11px; |
| font-weight: 700; |
| font-family: "Space Grotesk", sans-serif; |
| letter-spacing: 0.03em; |
| text-transform: uppercase; |
| border: 1px solid transparent; |
| } |
| |
| .chip.category { background: var(--brand-soft); color: var(--brand); border-color: #b7dccc; } |
| .chip.source { background: var(--accent-soft); color: #955016; border-color: #efc89f; } |
| .chip.status { background: #eef3ff; color: #3e4f86; border-color: #d2dbf6; } |
| |
| .title { |
| margin: 0; |
| font-size: 17px; |
| line-height: 1.3; |
| } |
| |
| .title a { |
| color: var(--ink); |
| text-decoration: none; |
| border-bottom: 1px solid transparent; |
| } |
| |
| .title a:hover { |
| border-bottom-color: currentColor; |
| } |
| |
| .meta { |
| color: var(--muted); |
| font-size: 13px; |
| line-height: 1.45; |
| margin: 0; |
| } |
| |
| .card footer { |
| margin-top: auto; |
| font-size: 12px; |
| color: var(--muted); |
| } |
| |
| .empty { |
| border: 1px dashed #b9c4bd; |
| border-radius: 12px; |
| padding: 24px; |
| background: #fcfcfa; |
| color: var(--muted); |
| text-align: center; |
| } |
| |
| @keyframes rise { |
| from { opacity: 0; transform: translateY(8px); } |
| to { opacity: 1; transform: translateY(0); } |
| } |
| |
| @media (max-width: 900px) { |
| .controls { |
| grid-template-columns: 1fr 1fr; |
| } |
| |
| .controls .field:first-child { |
| grid-column: span 2; |
| } |
| } |
| |
| @media (max-width: 560px) { |
| h1 { font-size: 28px; } |
| .controls { grid-template-columns: 1fr; } |
| .controls .field:first-child { grid-column: span 1; } |
| .summary { flex-direction: column; align-items: flex-start; } |
| } |
| </style> |
| </head> |
| <body> |
| <main class="wrap"> |
| <section class="hero"> |
| <div class="eyebrow">Pukhto Pashto</div> |
| <h1>Pashto Technology Resource Search</h1> |
| <p> |
| Search and filter verified and candidate resources that support Pashto in ASR, TTS, NLP, translation, tooling, and research. |
| </p> |
|
|
| <div class="controls"> |
| <div class="field"> |
| <label for="q">Search</label> |
| <input id="q" type="search" placeholder="Try: ASR, pbt_Arab, translation, speech" /> |
| </div> |
| <div class="field"> |
| <label for="category">Category</label> |
| <select id="category"></select> |
| </div> |
| <div class="field"> |
| <label for="source">Source</label> |
| <select id="source"></select> |
| </div> |
| <div class="field"> |
| <label for="task">Task</label> |
| <select id="task"></select> |
| </div> |
| <div class="field"> |
| <label for="status">Status</label> |
| <select id="status"></select> |
| </div> |
| </div> |
| </section> |
|
|
| <div class="summary"> |
| <span id="countText">Loading resources...</span> |
| <span class="badge" id="generatedAt">Catalog timestamp: -</span> |
| </div> |
|
|
| <section class="crawl" aria-label="Pashto resource categories"> |
| <p> |
| Browse or search resource entries covering Pashto datasets, speech recognition (ASR), text-to-speech (TTS), NLP, translation, tools, and benchmarks. |
| </p> |
| <p> |
| Project overview: <a href="https://github.com/Musawer1214/pashto-language-resources">Musawer1214/pashto-language-resources</a> |
| </p> |
| <ul class="crawl-links"> |
| <li><a href="https://github.com/Musawer1214/pashto-language-resources/blob/main/resources/datasets/README.md">Pashto datasets</a></li> |
| <li><a href="https://github.com/Musawer1214/pashto-language-resources/blob/main/resources/models/README.md">Pashto models</a></li> |
| <li><a href="https://github.com/Musawer1214/pashto-language-resources/blob/main/resources/benchmarks/README.md">Pashto benchmarks</a></li> |
| <li><a href="https://github.com/Musawer1214/pashto-language-resources/blob/main/resources/tools/README.md">Pashto tools</a></li> |
| <li><a href="https://github.com/Musawer1214/pashto-language-resources/blob/main/resources/papers/README.md">Pashto papers</a></li> |
| </ul> |
| </section> |
|
|
| <noscript> |
| JavaScript is needed for filtering, but the linked category pages above remain accessible. |
| </noscript> |
|
|
| <ul id="results" class="grid"></ul> |
| </main> |
|
|
| <script> |
| const state = { |
| all: [], |
| filtered: [] |
| }; |
| |
| const els = { |
| q: document.getElementById("q"), |
| category: document.getElementById("category"), |
| source: document.getElementById("source"), |
| task: document.getElementById("task"), |
| status: document.getElementById("status"), |
| results: document.getElementById("results"), |
| countText: document.getElementById("countText"), |
| generatedAt: document.getElementById("generatedAt") |
| }; |
| |
| function uniqSorted(values) { |
| return [...new Set(values.filter(Boolean))].sort((a, b) => a.localeCompare(b)); |
| } |
| |
| function fillSelect(select, options, allLabel) { |
| select.innerHTML = ""; |
| const allOption = document.createElement("option"); |
| allOption.value = ""; |
| allOption.textContent = allLabel; |
| select.appendChild(allOption); |
| for (const opt of options) { |
| const el = document.createElement("option"); |
| el.value = opt; |
| el.textContent = opt; |
| select.appendChild(el); |
| } |
| } |
| |
| function matchesQuery(resource, query) { |
| if (!query) return true; |
| const hay = [ |
| resource.title, |
| resource.summary, |
| resource.primary_use, |
| resource.category, |
| resource.source, |
| resource.status, |
| ...(resource.tags || []), |
| ...(resource.tasks || []), |
| ...(resource.markers || []), |
| resource.evidence_text |
| ].join(" ").toLowerCase(); |
| return hay.includes(query); |
| } |
| |
| function applyFilters() { |
| const q = els.q.value.trim().toLowerCase(); |
| const category = els.category.value; |
| const source = els.source.value; |
| const task = els.task.value; |
| const status = els.status.value; |
| |
| state.filtered = state.all.filter((resource) => { |
| if (!matchesQuery(resource, q)) return false; |
| if (category && resource.category !== category) return false; |
| if (source && resource.source !== source) return false; |
| if (status && resource.status !== status) return false; |
| if (task && !(resource.tasks || []).includes(task)) return false; |
| return true; |
| }); |
| |
| renderResults(); |
| } |
| |
| function chip(label, cls) { |
| return `<span class="chip ${cls}">${label}</span>`; |
| } |
| |
| function renderResults() { |
| const items = state.filtered; |
| els.countText.textContent = `${items.length} result${items.length === 1 ? "" : "s"} of ${state.all.length}`; |
| |
| if (!items.length) { |
| els.results.innerHTML = `<li class="empty">No matches. Try broadening filters or changing keywords.</li>`; |
| return; |
| } |
| |
| els.results.innerHTML = items.map((resource, idx) => ` |
| <li class="card" style="animation-delay:${Math.min(idx * 28, 320)}ms"> |
| <div class="chips"> |
| ${chip(resource.category, "category")} |
| ${chip(resource.source, "source")} |
| ${chip(resource.status, "status")} |
| </div> |
| <h2 class="title"><a href="${resource.url}" target="_blank" rel="noreferrer">${resource.title}</a></h2> |
| <p class="meta">${resource.summary}</p> |
| <p class="meta"><strong>Primary use:</strong> ${resource.primary_use}</p> |
| <p class="meta"><strong>Pashto evidence:</strong> <a href="${resource.evidence_url}" target="_blank" rel="noreferrer">${resource.evidence_text}</a></p> |
| <footer> |
| ${(resource.tasks || []).length ? `Tasks: ${resource.tasks.join(", ")}` : "Tasks: n/a"} |
| </footer> |
| </li> |
| `).join(""); |
| } |
| |
| async function load() { |
| try { |
| const res = await fetch("./resources.json", { cache: "no-store" }); |
| if (!res.ok) throw new Error(`HTTP ${res.status}`); |
| const payload = await res.json(); |
| state.all = payload.resources || []; |
| state.filtered = [...state.all]; |
| |
| fillSelect(els.category, uniqSorted(state.all.map((r) => r.category)), "All categories"); |
| fillSelect(els.source, uniqSorted(state.all.map((r) => r.source)), "All sources"); |
| fillSelect(els.status, uniqSorted(state.all.map((r) => r.status)), "All statuses"); |
| fillSelect( |
| els.task, |
| uniqSorted(state.all.flatMap((r) => r.tasks || [])), |
| "All tasks" |
| ); |
| |
| const generated = payload.generated_on ? new Date(payload.generated_on) : null; |
| els.generatedAt.textContent = generated && !Number.isNaN(generated.getTime()) |
| ? `Catalog timestamp: ${generated.toISOString()}` |
| : "Catalog timestamp: unknown"; |
| |
| applyFilters(); |
| } catch (err) { |
| els.countText.textContent = "Failed to load resources"; |
| els.results.innerHTML = `<li class="empty">Could not load search data. ${String(err)}</li>`; |
| } |
| } |
| |
| [els.q, els.category, els.source, els.task, els.status].forEach((el) => { |
| el.addEventListener("input", applyFilters); |
| el.addEventListener("change", applyFilters); |
| }); |
| |
| load(); |
| </script> |
| </body> |
| </html> |
|
|
|
|