Eklenecek kod:

```dataviewjs
const pages = dv.pages('"3. Resourses"').where(p => p.страница && p["всего страниц"]);
const container = this.container;

// === UI: Kategorilere göre filtre ===
const filterWrapper = document.createElement("div");
filterWrapper.style.display = "flex";
filterWrapper.style.gap = "1rem";
filterWrapper.style.marginBottom = "1rem";

// Kategoriler (tags)
const select = document.createElement("select");
const allOption = document.createElement("option");
allOption.textContent = "Tüm kategoriler";
allOption.value = "";
select.appendChild(allOption);

const allTags = new Set();
for (let p of pages) {
  const tags = Array.isArray(p.tags) ? p.tags : [p.tags];
  tags.forEach(t => t && allTags.add(t));
}
for (let tag of Array.from(allTags).sort()) {
  const opt = document.createElement("option");
  opt.textContent = tag;
  opt.value = tag;
  select.appendChild(opt);
}
filterWrapper.appendChild(select);

// === UI: Arama alanı ===
const searchInput = document.createElement("input");
searchInput.type = "text";
searchInput.placeholder = "🔍 Kitap ara...";
searchInput.style.flex = "1";
filterWrapper.appendChild(searchInput);

// === Tabloyu oluşturma ===
container.appendChild(filterWrapper);

function renderTable(selectedTag = "", searchTerm = "") {
  const oldTable = container.querySelector("table");
  if (oldTable) oldTable.remove();

  const table = document.createElement("table");
  table.className = "dataview table-view-table";

  const header = table.insertRow();
  ["📕 Kapak", "📘 Kitap", "✍️ Yazar", "📚 Kategori", "📖 Okundu", "📈 İlerleme çubuğu"].forEach(title => {
    const th = document.createElement("th");
    th.textContent = title;
    header.appendChild(th);
  });

  for (let p of pages) {
    const tagMatch = !selectedTag || (Array.isArray(p.tags) ? p.tags.includes(selectedTag) : p.tags === selectedTag);
    const searchMatch = !searchTerm || p.file.name.toLowerCase().includes(searchTerm.toLowerCase());

    if (!(tagMatch && searchMatch)) continue;

    const current = Number(p.страница);
    const total = Number(p["всего страниц"]);
    const percent = Math.round((current / total) * 100);
    const color = percent === 100 ? 'green' : 'orange';

    const row = table.insertRow();

    const cellCover = row.insertCell();
    cellCover.innerHTML = p.cover ? `<img src="${p.cover}" width="100" style="border-radius: 8px;">` : "—";

    const cellTitle = row.insertCell();
    const link = document.createElement("a");
    link.href = p.file.path;
    link.textContent = p.file.name;
    link.className = "internal-link";
    cellTitle.appendChild(link);

    const cellAuthor = row.insertCell();
    cellAuthor.textContent = p.Автор || "–";

    const cellTags = row.insertCell();
    cellTags.textContent = Array.isArray(p.tags) ? p.tags.join(", ") : (p.tags || "–");

    const cellProgressText = row.insertCell();
    cellProgressText.textContent = `${current} / ${total}`;

    const cellBar = row.insertCell();
    const progressBarContainer = document.createElement("div");
    progressBarContainer.style.background = "#eee";
    progressBarContainer.style.borderRadius = "6px";
    progressBarContainer.style.height = "16px";
    progressBarContainer.style.width = "100%";
    const progressBar = document.createElement("div");
    progressBar.style.background = color;
    progressBar.style.height = "100%";
    progressBar.style.borderRadius = "6px";
    progressBar.style.width = `${percent}%`;
    progressBarContainer.appendChild(progressBar);
    const percentText = document.createElement("div");
    percentText.style.fontSize = "12px";
    percentText.style.textAlign = "right";
    percentText.textContent = `${percent}%`;
    cellBar.appendChild(progressBarContainer);
    cellBar.appendChild(percentText);
  }

  container.appendChild(table);
}

// === Dinleyiciler ===
select.onchange = () => renderTable(select.value, searchInput.value);
searchInput.oninput = () => renderTable(select.value, searchInput.value);

// Başlatma
renderTable();```

from “const pages = dv.pages(‘“3. Resourses”’)” — YAML’lı notlarının bulunduğu kendi yolunla değiştir Son üç apostrof karakterini yeni bir satıra taşı


🧠 Bu kodu daha derin anlamak isteyenler için açıklama:

🔍 1. Kitapları klasörden yükleme

const pages = dv.pages('"3. Resourses"')
  .where(p => p.страница && p["всего страниц"]);

Burada:

  • "3. Resourses" klasöründeki tüm notları alıyoruz (yolu kendine göre değiştir).

  • Yalnızca страница (mevcut sayfa) ve всего страниц (toplam sayfa) alanları olanları filtreliyoruz.

📌 Yani her kitaptan ne kadar okuduğunu takip ediyorsun — doğrudan YAML’da.


🧰 2. Arayüzü oluşturma — filtre ve arama

const filterWrapper = document.createElement("div");
...

Burada iki kontrol oluşturulur:

  • kategorili bir açılır liste (tags’e göre);

  • dosya adına göre bir arama alanı (not adı = kitap başlığı).

📌 Her şey document.createElement ile elle yapılır, böylece öğe doğrudan nota gömülür.


🧠 3. Benzersiz kategorileri toplama

for (let p of pages) {
  const tags = Array.isArray(p.tags) ? p.tags : [p.tags];
  tags.forEach(t => t && allTags.add(t));
}

Tüm kitapları gezip benzersiz etiketleri (kategorileri) bir listeye topluyoruz.


📋 4. Kitap tablosunu çizme

function renderTable(selectedTag = "", searchTerm = "") {

renderTable fonksiyonu:

  • kitapları kategoriye ve aramaya göre filtreler;

  • kapaklar, yazarlar, ilerlemeyle bir tablo oluşturur;

  • her yeni filtre/aramada tabloyu yeniden oluşturur.

📌 Tabloyu canlı ve güncellenebilir yapan tam da bu fonksiyondur.


🖼️ 5. Bir tablo satırında ne gösterilir?

Her satırda 6 hücre var:

SütunNe gösterir
📕 KapakYAML’da cover: belirtilmişse görsel
📘 KitapKitap başlığı — nota bir bağlantı olarak
✍️ YazarYAML’dan Автор: alanı
📚 KategoriKitabın etiketleri
📖 Okundu23 / 200 formatı
📈 İlerlemeGörsel bir ilerleme çubuğu

🌡️ İlerleme çubuğu iş başında

const percent = Math.round((current / total) * 100);
const color = percent === 100 ? 'green' : 'orange';
  • Okunan % hesaplanır;

  • Sonuna kadar okuduysan — yeşil;

  • Hâlâ okuyorsan — turuncu.

Doğrudan Obsidian’da görsel bir gösterge — bildiğin takipçilerdeki gibi.


🎮 6. “Hayat” katma

select.onchange = () => renderTable(select.value, searchInput.value);
searchInput.oninput = () => renderTable(select.value, searchInput.value);

Kullanıcı kategoriyi değiştirdiğinde ya da bir sorgu yazdığında — tablo filtreleri dikkate alarak yeniden çizilir.


🧩 Çalıştırmak için ne gerekiyor

  • Kitaplar hakkında notların olduğu bir klasör;

  • Her notta şu alanlarla YAML olmalı:

cover: https://link.to/cover.jpg
Автор: Yazar Adı
tags: [Üretkenlik, Felsefe]
страница: 80
всего страниц: 200

💥 Ne elde edersin

  • Filtre ve aramalı bir kitap kataloğu;

  • Güzel bir görsel — kapaklar, ilerleme, kategoriler;

  • Doğrudan Obsidian’da çalışır, dış servisler olmadan.