musaw commited on
Commit
3614ee2
·
1 Parent(s): 204c5d9

fix(ui): prevent card overflow and improve task labeling for v1.1.1

Browse files
CHANGELOG.md CHANGED
@@ -20,6 +20,16 @@ and this project uses semantic version tags with a fixed role per figure:
20
  ### Fixed
21
  - None yet.
22
 
 
 
 
 
 
 
 
 
 
 
23
  ## [v1.0.1] - 2026-02-18
24
  ### Added
25
  - Promoted 6 high-confidence, non-duplicate Hugging Face resources to verified catalog:
 
20
  ### Fixed
21
  - None yet.
22
 
23
+ ## [v1.1.1] - 2026-02-18
24
+ ### Changed
25
+ - Improved search-page readability and usability in `docs/search/index.html`.
26
+ - Expanded short task labels into clearer full-form labels in UI controls and resource cards.
27
+ - Standardized title casing for key UI labels and actions.
28
+
29
+ ### Fixed
30
+ - Prevented long resource titles and long unbroken strings from overflowing card boundaries.
31
+ - Improved capitalization and display formatting for source and task text in search results.
32
+
33
  ## [v1.0.1] - 2026-02-18
34
  ### Added
35
  - Promoted 6 high-confidence, non-duplicate Hugging Face resources to verified catalog:
CITATION.cff CHANGED
@@ -2,7 +2,7 @@ cff-version: 1.2.0
2
  message: "If you use this repository, please cite it."
3
  title: "Pashto Language Resources Hub (Pukhto/Pashto)"
4
  type: software
5
- version: 1.0.1
6
  date-released: 2026-02-18
7
  license: Apache-2.0
8
  repository-code: "https://github.com/Musawer1214/pashto-language-resources"
@@ -20,3 +20,4 @@ keywords:
20
  - machine translation
21
  - language resources
22
 
 
 
2
  message: "If you use this repository, please cite it."
3
  title: "Pashto Language Resources Hub (Pukhto/Pashto)"
4
  type: software
5
+ version: 1.1.1
6
  date-released: 2026-02-18
7
  license: Apache-2.0
8
  repository-code: "https://github.com/Musawer1214/pashto-language-resources"
 
20
  - machine translation
21
  - language resources
22
 
23
+
README.md CHANGED
@@ -73,7 +73,7 @@ python -m pytest -q
73
  ## Releases
74
 
75
  - Release notes index: [docs/releases/README.md](docs/releases/README.md)
76
- - Latest release notes: [v1.0.1](docs/releases/v1.0.1.md)
77
  - Changelog: [CHANGELOG.md](CHANGELOG.md)
78
 
79
  ## Contributing
@@ -82,3 +82,4 @@ python -m pytest -q
82
  - Community communication: [community/COMMUNICATION.md](community/COMMUNICATION.md)
83
  - Resource guidelines: [docs/dataset_guidelines.md](docs/dataset_guidelines.md)
84
 
 
 
73
  ## Releases
74
 
75
  - Release notes index: [docs/releases/README.md](docs/releases/README.md)
76
+ - Latest release notes: [v1.1.1](docs/releases/v1.1.1.md)
77
  - Changelog: [CHANGELOG.md](CHANGELOG.md)
78
 
79
  ## Contributing
 
82
  - Community communication: [community/COMMUNICATION.md](community/COMMUNICATION.md)
83
  - Resource guidelines: [docs/dataset_guidelines.md](docs/dataset_guidelines.md)
84
 
85
+
docs/index.md CHANGED
@@ -43,7 +43,7 @@ description: Open-source Pashto (Pukhto/Pashto) datasets, models, benchmarks, AS
43
  ## Releases
44
 
45
  - Release notes index: [releases/README.md](releases/README.md)
46
- - Current release notes: [v1.0.1](releases/v1.0.1.md)
47
  - Changelog: [../CHANGELOG.md](../CHANGELOG.md)
48
 
49
  ## Contribution
@@ -58,3 +58,4 @@ Start here:
58
 
59
  This project is released under Apache 2.0. See [LICENSE](../LICENSE).
60
 
 
 
43
  ## Releases
44
 
45
  - Release notes index: [releases/README.md](releases/README.md)
46
+ - Current release notes: [v1.1.1](releases/v1.1.1.md)
47
  - Changelog: [../CHANGELOG.md](../CHANGELOG.md)
48
 
49
  ## Contribution
 
58
 
59
  This project is released under Apache 2.0. See [LICENSE](../LICENSE).
60
 
61
+
docs/releases/README.md CHANGED
@@ -4,13 +4,15 @@ This directory stores versioned release notes for the project.
4
 
5
  ## Current
6
 
7
- - [v1.0.1](v1.0.1.md)
8
 
9
  ## Previous
10
 
 
11
  - [v1.0.0](v1.0.0.md)
12
 
13
  ## Notes
14
 
 
15
  - `v1.0.1` is a resource-catalog release (third figure update).
16
  - Earlier bootstrap history (`v0.1`) remains documented in [../../CHANGELOG.md](../../CHANGELOG.md).
 
4
 
5
  ## Current
6
 
7
+ - [v1.1.1](v1.1.1.md)
8
 
9
  ## Previous
10
 
11
+ - [v1.0.1](v1.0.1.md)
12
  - [v1.0.0](v1.0.0.md)
13
 
14
  ## Notes
15
 
16
+ - `v1.1.1` is a code-fix release (middle figure update).
17
  - `v1.0.1` is a resource-catalog release (third figure update).
18
  - Earlier bootstrap history (`v0.1`) remains documented in [../../CHANGELOG.md](../../CHANGELOG.md).
docs/releases/v1.1.1.md ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Release Notes: v1.1.1
2
+
3
+ Release date: 2026-02-18
4
+ Tag: `v1.1.1`
5
+
6
+ ## Summary
7
+
8
+ Code-fix release focused on search-page UI correctness, readability, and terminology clarity.
9
+
10
+ ## Highlights
11
+
12
+ - Fixed long-text overflow so content remains inside resource cards.
13
+ - Improved task labels to use clear full forms where needed.
14
+ - Applied better capitalization across key search UI labels.
15
+ - Improved rendering consistency for long titles and source text.
16
+
17
+ ## Validation
18
+
19
+ - `python scripts/check_links.py`
20
+ - `python scripts/validate_resource_catalog.py`
21
+ - `python scripts/validate_normalization.py data/processed/normalization_seed_v0.1.tsv`
22
+ - `python -m pytest -q`
23
+
24
+ ## Versioning Rule Applied
25
+
26
+ This release follows the project rule:
27
+
28
+ - `vMAJOR.CODE.RESOURCE`
29
+ - Code-fix updates increment the middle figure.
30
+
31
+ ## Compare
32
+
33
+ - [GitHub compare: v1.0.1...v1.1.1](https://github.com/Musawer1214/pashto-language-resources/compare/v1.0.1...v1.1.1)
docs/search/index.html CHANGED
@@ -10,7 +10,7 @@ permalink: /search/
10
  <meta charset="utf-8">
11
  <meta name="viewport" content="width=device-width, initial-scale=1">
12
  <title>Pashto Resource Search</title>
13
- <meta name="description" content="Search verified Pashto (Pukhto/Pashto) resources for ASR, TTS, NLP, machine translation, tools, datasets, models, and benchmarks.">
14
  <meta name="keywords" content="Pashto resources, Pukhto resources, Pashto datasets, Pashto ASR, Pashto TTS, Pashto NLP, Pashto machine translation, Pashto benchmarks">
15
  <meta name="robots" content="index,follow,max-image-preview:large">
16
  <link rel="canonical" href="https://musawer1214.github.io/pashto-language-resources/search/">
@@ -28,7 +28,7 @@ permalink: /search/
28
  "@type": "CollectionPage",
29
  "name": "Pashto Resource Search",
30
  "url": "https://musawer1214.github.io/pashto-language-resources/search/",
31
- "description": "Search verified and candidate Pashto resources for ASR, TTS, NLP, MT, tools, datasets, and benchmarks.",
32
  "inLanguage": "en",
33
  "about": [
34
  "Pashto datasets",
@@ -354,12 +354,18 @@ permalink: /search/
354
  margin: 0;
355
  font-size: 17px;
356
  line-height: 1.3;
 
 
357
  }
358
 
359
  .title a {
360
  color: var(--ink);
361
  text-decoration: none;
362
  border-bottom: 1px solid transparent;
 
 
 
 
363
  }
364
 
365
  .title a:hover { border-bottom-color: currentColor; }
@@ -369,6 +375,8 @@ permalink: /search/
369
  color: var(--muted);
370
  line-height: 1.48;
371
  font-size: 13px;
 
 
372
  }
373
 
374
  .meta-links {
@@ -384,12 +392,18 @@ permalink: /search/
384
  font-weight: 700;
385
  color: var(--brand);
386
  text-decoration: none;
 
 
 
 
387
  }
388
 
389
  .tasks {
390
  font-size: 12px;
391
  color: var(--muted);
392
  margin: 0;
 
 
393
  }
394
 
395
  .empty {
@@ -446,7 +460,7 @@ permalink: /search/
446
  <p class="eyebrow">Pukhto / Pashto Resources</p>
447
  <h1>Pashto Technology Resource Search</h1>
448
  <p class="subtitle">
449
- Filter verified and candidate resources for ASR, TTS, NLP, translation, tools, and benchmark work.
450
  Share search states with URL parameters and jump quickly to high-intent pages.
451
  </p>
452
  </div>
@@ -458,9 +472,9 @@ permalink: /search/
458
  </div>
459
  <nav class="quick-links" aria-label="Quick links">
460
  <a class="pill-link" href="../">Docs Home</a>
461
- <a class="pill-link" href="../pashto_datasets.md">Datasets Page</a>
462
- <a class="pill-link" href="../pashto_asr.md">ASR Page</a>
463
- <a class="pill-link" href="../pashto_tts.md">TTS Page</a>
464
  <a class="pill-link" href="https://github.com/Musawer1214/pashto-language-resources">GitHub</a>
465
  <a class="pill-link" href="https://huggingface.co/Musawer14/pashto-language-resources">Hugging Face</a>
466
  </nav>
@@ -470,7 +484,7 @@ permalink: /search/
470
  <div class="controls">
471
  <div class="field search">
472
  <label for="q">Search</label>
473
- <input id="q" type="search" placeholder="Try: asr, pbt_arab, translation, speech, benchmark" autocomplete="off">
474
  </div>
475
  <div class="field">
476
  <label for="category">Category</label>
@@ -501,12 +515,12 @@ permalink: /search/
501
 
502
  <div class="action-row">
503
  <div class="group" role="group" aria-label="Result view mode">
504
- <button type="button" class="btn active" id="viewGrid">Grid view</button>
505
- <button type="button" class="btn" id="viewList">List view</button>
506
  </div>
507
  <div class="group">
508
- <button type="button" class="btn light" id="clearFilters">Clear filters</button>
509
- <button type="button" class="btn brand" id="copyLink">Copy search link</button>
510
  </div>
511
  </div>
512
 
@@ -516,7 +530,7 @@ permalink: /search/
516
  <button type="button" class="intent" data-intent="tts">TTS</button>
517
  <button type="button" class="intent" data-intent="nlp">NLP</button>
518
  <button type="button" class="intent" data-intent="mt">Translation</button>
519
- <button type="button" class="intent" data-intent="verified">Verified only</button>
520
  </div>
521
  </section>
522
 
@@ -570,6 +584,113 @@ permalink: /search/
570
  intents: [...document.querySelectorAll(".intent")]
571
  };
572
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
573
  function esc(value) {
574
  return String(value || "")
575
  .replace(/&/g, "&amp;")
@@ -583,7 +704,7 @@ permalink: /search/
583
  return [...new Set(values.filter(Boolean))].sort((a, b) => a.localeCompare(b));
584
  }
585
 
586
- function fillSelect(select, options, allLabel) {
587
  select.innerHTML = "";
588
  const allOption = document.createElement("option");
589
  allOption.value = "";
@@ -592,7 +713,7 @@ permalink: /search/
592
  for (const opt of options) {
593
  const entry = document.createElement("option");
594
  entry.value = opt;
595
- entry.textContent = opt;
596
  select.appendChild(entry);
597
  }
598
  }
@@ -680,33 +801,33 @@ permalink: /search/
680
  els.countText.textContent = `${items.length} result${items.length === 1 ? "" : "s"} of ${state.all.length}`;
681
 
682
  if (!items.length) {
683
- els.results.innerHTML = '<li class="empty">No matches. Try broadening filters or clearing one filter at a time.</li>';
684
  return;
685
  }
686
 
687
  els.results.innerHTML = items.map((resource) => {
688
  const title = esc(resource.title || "Untitled resource");
689
  const url = esc(resource.url || "#");
690
- const summary = esc(resource.summary || "No summary provided.");
691
- const primaryUse = esc(resource.primary_use || "n/a");
692
- const evidenceText = esc(resource.evidence_text || "evidence link");
693
  const evidenceUrl = esc(resource.evidence_url || resource.url || "#");
694
- const tasks = (resource.tasks || []).map((t) => esc(t)).join(", ") || "n/a";
695
 
696
  return `
697
  <li class="card">
698
  <div class="chips">
699
- ${chip(resource.category || "unknown", "category")}
700
- ${chip(resource.source || "unknown", "source")}
701
- ${chip(resource.status || "unknown", "status")}
702
  </div>
703
  <h2 class="title"><a href="${url}" target="_blank" rel="noreferrer">${title}</a></h2>
704
  <p class="text">${summary}</p>
705
- <p class="text"><strong>Primary use:</strong> ${primaryUse}</p>
706
  <p class="tasks"><strong>Tasks:</strong> ${tasks}</p>
707
  <div class="meta-links">
708
- <a class="mini-link" href="${url}" target="_blank" rel="noreferrer">Open resource</a>
709
- <a class="mini-link" href="${evidenceUrl}" target="_blank" rel="noreferrer">Pashto evidence: ${evidenceText}</a>
710
  </div>
711
  </li>
712
  `;
@@ -772,11 +893,11 @@ permalink: /search/
772
  async function copySearchLink() {
773
  try {
774
  await navigator.clipboard.writeText(window.location.href);
775
- els.copyLink.textContent = "Link copied";
776
- setTimeout(() => { els.copyLink.textContent = "Copy search link"; }, 1200);
777
  } catch (_error) {
778
- els.copyLink.textContent = "Copy failed";
779
- setTimeout(() => { els.copyLink.textContent = "Copy search link"; }, 1200);
780
  }
781
  }
782
 
@@ -788,10 +909,10 @@ permalink: /search/
788
 
789
  state.all = payload.resources || [];
790
 
791
- fillSelect(els.category, uniqSorted(state.all.map((r) => r.category)), "All categories");
792
- fillSelect(els.source, uniqSorted(state.all.map((r) => r.source)), "All sources");
793
- fillSelect(els.status, uniqSorted(state.all.map((r) => r.status)), "All statuses");
794
- fillSelect(els.task, uniqSorted(state.all.flatMap((r) => r.tasks || [])), "All tasks");
795
 
796
  updateMetrics();
797
 
@@ -825,3 +946,6 @@ permalink: /search/
825
  </script>
826
  </body>
827
  </html>
 
 
 
 
10
  <meta charset="utf-8">
11
  <meta name="viewport" content="width=device-width, initial-scale=1">
12
  <title>Pashto Resource Search</title>
13
+ <meta name="description" content="Search verified Pashto (Pukhto/Pashto) resources for Automatic Speech Recognition (ASR), Text-to-Speech (TTS), Natural Language Processing (NLP), machine translation, tools, datasets, models, and benchmarks.">
14
  <meta name="keywords" content="Pashto resources, Pukhto resources, Pashto datasets, Pashto ASR, Pashto TTS, Pashto NLP, Pashto machine translation, Pashto benchmarks">
15
  <meta name="robots" content="index,follow,max-image-preview:large">
16
  <link rel="canonical" href="https://musawer1214.github.io/pashto-language-resources/search/">
 
28
  "@type": "CollectionPage",
29
  "name": "Pashto Resource Search",
30
  "url": "https://musawer1214.github.io/pashto-language-resources/search/",
31
+ "description": "Search verified and candidate Pashto resources for Automatic Speech Recognition (ASR), Text-to-Speech (TTS), Natural Language Processing (NLP), machine translation, tools, datasets, and benchmarks.",
32
  "inLanguage": "en",
33
  "about": [
34
  "Pashto datasets",
 
354
  margin: 0;
355
  font-size: 17px;
356
  line-height: 1.3;
357
+ overflow-wrap: anywhere;
358
+ word-break: break-word;
359
  }
360
 
361
  .title a {
362
  color: var(--ink);
363
  text-decoration: none;
364
  border-bottom: 1px solid transparent;
365
+ display: inline-block;
366
+ max-width: 100%;
367
+ overflow-wrap: anywhere;
368
+ word-break: break-word;
369
  }
370
 
371
  .title a:hover { border-bottom-color: currentColor; }
 
375
  color: var(--muted);
376
  line-height: 1.48;
377
  font-size: 13px;
378
+ overflow-wrap: anywhere;
379
+ word-break: break-word;
380
  }
381
 
382
  .meta-links {
 
392
  font-weight: 700;
393
  color: var(--brand);
394
  text-decoration: none;
395
+ display: inline-block;
396
+ max-width: 100%;
397
+ overflow-wrap: anywhere;
398
+ word-break: break-word;
399
  }
400
 
401
  .tasks {
402
  font-size: 12px;
403
  color: var(--muted);
404
  margin: 0;
405
+ overflow-wrap: anywhere;
406
+ word-break: break-word;
407
  }
408
 
409
  .empty {
 
460
  <p class="eyebrow">Pukhto / Pashto Resources</p>
461
  <h1>Pashto Technology Resource Search</h1>
462
  <p class="subtitle">
463
+ Filter verified and candidate resources for Automatic Speech Recognition (ASR), Text-to-Speech (TTS), Natural Language Processing (NLP), translation, tools, and benchmark work.
464
  Share search states with URL parameters and jump quickly to high-intent pages.
465
  </p>
466
  </div>
 
472
  </div>
473
  <nav class="quick-links" aria-label="Quick links">
474
  <a class="pill-link" href="../">Docs Home</a>
475
+ <a class="pill-link" href="../pashto_datasets.html">Datasets Page</a>
476
+ <a class="pill-link" href="../pashto_asr.html">ASR Page</a>
477
+ <a class="pill-link" href="../pashto_tts.html">TTS Page</a>
478
  <a class="pill-link" href="https://github.com/Musawer1214/pashto-language-resources">GitHub</a>
479
  <a class="pill-link" href="https://huggingface.co/Musawer14/pashto-language-resources">Hugging Face</a>
480
  </nav>
 
484
  <div class="controls">
485
  <div class="field search">
486
  <label for="q">Search</label>
487
+ <input id="q" type="search" placeholder="Try: Automatic Speech Recognition, PBT_Arab, Translation, Speech, Benchmark" autocomplete="off">
488
  </div>
489
  <div class="field">
490
  <label for="category">Category</label>
 
515
 
516
  <div class="action-row">
517
  <div class="group" role="group" aria-label="Result view mode">
518
+ <button type="button" class="btn active" id="viewGrid">Grid View</button>
519
+ <button type="button" class="btn" id="viewList">List View</button>
520
  </div>
521
  <div class="group">
522
+ <button type="button" class="btn light" id="clearFilters">Clear Filters</button>
523
+ <button type="button" class="btn brand" id="copyLink">Copy Search Link</button>
524
  </div>
525
  </div>
526
 
 
530
  <button type="button" class="intent" data-intent="tts">TTS</button>
531
  <button type="button" class="intent" data-intent="nlp">NLP</button>
532
  <button type="button" class="intent" data-intent="mt">Translation</button>
533
+ <button type="button" class="intent" data-intent="verified">Verified Only</button>
534
  </div>
535
  </section>
536
 
 
584
  intents: [...document.querySelectorAll(".intent")]
585
  };
586
 
587
+ const TASK_LABELS = {
588
+ "asr": "Automatic Speech Recognition (ASR)",
589
+ "tts": "Text-to-Speech (TTS)",
590
+ "nlp": "Natural Language Processing (NLP)",
591
+ "mt": "Machine Translation (MT)",
592
+ "llm": "Large Language Model (LLM)",
593
+ "ocr": "Optical Character Recognition (OCR)",
594
+ "pos-tagging": "Part-of-Speech Tagging",
595
+ "benchmarking": "Benchmarking",
596
+ "classification": "Classification",
597
+ "demo": "Demo",
598
+ "dictionary": "Dictionary",
599
+ "research": "Research",
600
+ "sentiment": "Sentiment Analysis",
601
+ "tooling": "Tooling",
602
+ "translation": "Translation"
603
+ };
604
+
605
+ const CATEGORY_LABELS = {
606
+ "dataset": "Dataset",
607
+ "model": "Model",
608
+ "benchmark": "Benchmark",
609
+ "tool": "Tool",
610
+ "paper": "Paper",
611
+ "project": "Project",
612
+ "code": "Code"
613
+ };
614
+
615
+ const SOURCE_LABELS = {
616
+ "huggingface": "Hugging Face",
617
+ "mozilla": "Mozilla",
618
+ "kaggle": "Kaggle",
619
+ "github": "GitHub",
620
+ "gitlab": "GitLab",
621
+ "arxiv": "arXiv",
622
+ "openalex": "OpenAlex",
623
+ "crossref": "Crossref",
624
+ "zenodo": "Zenodo",
625
+ "dataverse": "Dataverse",
626
+ "datacite": "DataCite",
627
+ "meta": "Meta",
628
+ "other": "Other"
629
+ };
630
+
631
+ const STATUS_LABELS = {
632
+ "verified": "Verified",
633
+ "candidate": "Candidate"
634
+ };
635
+
636
+ function toTitleCase(value) {
637
+ return String(value || "")
638
+ .replace(/[_-]+/g, " ")
639
+ .split(/\s+/)
640
+ .filter(Boolean)
641
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
642
+ .join(" ");
643
+ }
644
+
645
+ function replaceAbbreviation(text, shortForm, expanded) {
646
+ const fullPhrase = expanded.replace(/\s*\([^)]*\)\s*$/, "");
647
+ if (new RegExp(fullPhrase, "i").test(text)) {
648
+ return text;
649
+ }
650
+ return text.replace(new RegExp(`\\b${shortForm}\\b`, "gi"), expanded);
651
+ }
652
+
653
+ function formatDisplayText(value) {
654
+ let text = String(value || "").trim();
655
+ if (!text) return text;
656
+
657
+ text = text
658
+ .replace(/\bhuggingface\b/gi, "Hugging Face")
659
+ .replace(/\bgithub\b/gi, "GitHub")
660
+ .replace(/\bgitlab\b/gi, "GitLab")
661
+ .replace(/\bopenalex\b/gi, "OpenAlex")
662
+ .replace(/\barxiv\b/gi, "arXiv");
663
+
664
+ text = replaceAbbreviation(text, "ASR", "Automatic Speech Recognition (ASR)");
665
+ text = replaceAbbreviation(text, "TTS", "Text-to-Speech (TTS)");
666
+ text = replaceAbbreviation(text, "NLP", "Natural Language Processing (NLP)");
667
+ text = replaceAbbreviation(text, "MT", "Machine Translation (MT)");
668
+ text = replaceAbbreviation(text, "LLM", "Large Language Model (LLM)");
669
+ text = replaceAbbreviation(text, "OCR", "Optical Character Recognition (OCR)");
670
+
671
+ return text.charAt(0).toUpperCase() + text.slice(1);
672
+ }
673
+
674
+ function formatTaskLabel(value) {
675
+ const key = String(value || "").toLowerCase();
676
+ return TASK_LABELS[key] || toTitleCase(value);
677
+ }
678
+
679
+ function formatCategoryLabel(value) {
680
+ const key = String(value || "").toLowerCase();
681
+ return CATEGORY_LABELS[key] || toTitleCase(value);
682
+ }
683
+
684
+ function formatSourceLabel(value) {
685
+ const key = String(value || "").toLowerCase();
686
+ return SOURCE_LABELS[key] || toTitleCase(value);
687
+ }
688
+
689
+ function formatStatusLabel(value) {
690
+ const key = String(value || "").toLowerCase();
691
+ return STATUS_LABELS[key] || toTitleCase(value);
692
+ }
693
+
694
  function esc(value) {
695
  return String(value || "")
696
  .replace(/&/g, "&amp;")
 
704
  return [...new Set(values.filter(Boolean))].sort((a, b) => a.localeCompare(b));
705
  }
706
 
707
+ function fillSelect(select, options, allLabel, labelFormatter = toTitleCase) {
708
  select.innerHTML = "";
709
  const allOption = document.createElement("option");
710
  allOption.value = "";
 
713
  for (const opt of options) {
714
  const entry = document.createElement("option");
715
  entry.value = opt;
716
+ entry.textContent = labelFormatter(opt);
717
  select.appendChild(entry);
718
  }
719
  }
 
801
  els.countText.textContent = `${items.length} result${items.length === 1 ? "" : "s"} of ${state.all.length}`;
802
 
803
  if (!items.length) {
804
+ els.results.innerHTML = '<li class="empty">No Matches. Try Broadening Filters or Clearing One Filter at a Time.</li>';
805
  return;
806
  }
807
 
808
  els.results.innerHTML = items.map((resource) => {
809
  const title = esc(resource.title || "Untitled resource");
810
  const url = esc(resource.url || "#");
811
+ const summary = esc(formatDisplayText(resource.summary || "No summary provided."));
812
+ const primaryUse = esc(formatDisplayText(resource.primary_use || "Not available"));
813
+ const evidenceText = esc(formatDisplayText(resource.evidence_text || "Evidence link"));
814
  const evidenceUrl = esc(resource.evidence_url || resource.url || "#");
815
+ const tasks = (resource.tasks || []).map((t) => esc(formatTaskLabel(t))).join(", ") || "Not available";
816
 
817
  return `
818
  <li class="card">
819
  <div class="chips">
820
+ ${chip(formatCategoryLabel(resource.category || "unknown"), "category")}
821
+ ${chip(formatSourceLabel(resource.source || "unknown"), "source")}
822
+ ${chip(formatStatusLabel(resource.status || "unknown"), "status")}
823
  </div>
824
  <h2 class="title"><a href="${url}" target="_blank" rel="noreferrer">${title}</a></h2>
825
  <p class="text">${summary}</p>
826
+ <p class="text"><strong>Primary Use:</strong> ${primaryUse}</p>
827
  <p class="tasks"><strong>Tasks:</strong> ${tasks}</p>
828
  <div class="meta-links">
829
+ <a class="mini-link" href="${url}" target="_blank" rel="noreferrer">Open Resource</a>
830
+ <a class="mini-link" href="${evidenceUrl}" target="_blank" rel="noreferrer">Pashto Evidence: ${evidenceText}</a>
831
  </div>
832
  </li>
833
  `;
 
893
  async function copySearchLink() {
894
  try {
895
  await navigator.clipboard.writeText(window.location.href);
896
+ els.copyLink.textContent = "Link Copied";
897
+ setTimeout(() => { els.copyLink.textContent = "Copy Search Link"; }, 1200);
898
  } catch (_error) {
899
+ els.copyLink.textContent = "Copy Failed";
900
+ setTimeout(() => { els.copyLink.textContent = "Copy Search Link"; }, 1200);
901
  }
902
  }
903
 
 
909
 
910
  state.all = payload.resources || [];
911
 
912
+ fillSelect(els.category, uniqSorted(state.all.map((r) => r.category)), "All Categories", formatCategoryLabel);
913
+ fillSelect(els.source, uniqSorted(state.all.map((r) => r.source)), "All Sources", formatSourceLabel);
914
+ fillSelect(els.status, uniqSorted(state.all.map((r) => r.status)), "All Statuses", formatStatusLabel);
915
+ fillSelect(els.task, uniqSorted(state.all.flatMap((r) => r.tasks || [])), "All Tasks", formatTaskLabel);
916
 
917
  updateMetrics();
918
 
 
946
  </script>
947
  </body>
948
  </html>
949
+
950
+
951
+
pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
 
5
  [project]
6
  name = "pashto-language-resources"
7
- version = "1.0.1"
8
  description = "Open Pashto language resources for ASR, TTS, NLP, and benchmarks"
9
  requires-python = ">=3.10"
10
  readme = "README.md"
@@ -37,3 +37,4 @@ packages = []
37
 
38
 
39
 
 
 
4
 
5
  [project]
6
  name = "pashto-language-resources"
7
+ version = "1.1.1"
8
  description = "Open Pashto language resources for ASR, TTS, NLP, and benchmarks"
9
  requires-python = ">=3.10"
10
  readme = "README.md"
 
37
 
38
 
39
 
40
+