## Для создания вот такой таблицы, вам нужны установить плагин Dataview, а также включить в заметке YAML
![[Pasted image 20250526141546.png]]
Код для вставки:
```
```dataviewjs
const pages = dv.pages('"3. Resourses"').where(p => p.страница && p["всего страниц"]);
const container = this.container;
// === UI: Фильтр по категориям ===
const filterWrapper = document.createElement("div");
filterWrapper.style.display = "flex";
filterWrapper.style.gap = "1rem";
filterWrapper.style.marginBottom = "1rem";
// Категории (tags)
const select = document.createElement("select");
const allOption = document.createElement("option");
allOption.textContent = "Все категории";
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: Поле поиска ===
const searchInput = document.createElement("input");
searchInput.type = "text";
searchInput.placeholder = "🔍 Поиск книги...";
searchInput.style.flex = "1";
filterWrapper.appendChild(searchInput);
// === Рендер таблицы ===
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();
["📕 Обложка", "📘 Книга", "✍️ Автор", "📚 Категория", "📖 Прочитано", "📈 Прогресс-бар"].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);
}
// === Слушатели ===
select.onchange = () => renderTable(select.value, searchInput.value);
searchInput.oninput = () => renderTable(select.value, searchInput.value);
// Инициализация
renderTable();```
```
-> from "const pages = dv.pages('"3. Resourses"')" — заменить на свой путь, в котором лежат наши заметки с YAML
-> Последние три символа апострофа перенести на новую строку
---
### 🧠 Пояснение для тех, кто хочет глубже понимать о чем этот код:
#### 🔍 1. Загружаем книги из папки
```js
const pages = dv.pages('"3. Resourses"')
.where(p => p.страница && p["всего страниц"]);
```
Здесь мы:
- Берём все заметки из папки `"3. Resourses"` (замени путь под себя).
- Фильтруем только те, где есть поля `страница` (текущая страница) и `всего страниц`.
📌 То есть ты отслеживаешь, сколько прочитал от каждой книги — прямо в YAML.
---
#### 🧰 2. Создаём интерфейс — фильтр и поиск
```js
const filterWrapper = document.createElement("div");
...
```
Здесь создаются **два элемента управления**:
- выпадающий список с категориями (по `tags`);
- поле поиска по названию файла (имя заметки = название книги).
📌 Всё делается вручную через `document.createElement`, чтобы элемент был встроен прямо в заметку.
---
#### 🧠 3. Собираем уникальные категории
```js
for (let p of pages) {
const tags = Array.isArray(p.tags) ? p.tags : [p.tags];
tags.forEach(t => t && allTags.add(t));
}
```
Мы обходим все книги и собираем **уникальные теги** (категории) в список.
---
#### 📋 4. Рисуем таблицу книг
```js
function renderTable(selectedTag = "", searchTerm = "") {
```
Функция `renderTable`:
- фильтрует книги по категории и поиску;
- создаёт таблицу с обложками, авторами, прогрессом;
- пересоздаёт таблицу при каждом новом фильтре/поиске.
📌 Именно эта функция делает твою таблицу **живой и обновляемой**.
---
#### 🖼️ 5. Что выводится в строке таблицы?
В каждой строке — 6 ячеек:
|Колонка|Что показывает|
|---|---|
|📕 Обложка|Картинка, если указана `cover:` в YAML|
|📘 Книга|Название книги — как ссылка на заметку|
|✍️ Автор|Поле `Автор:` из YAML|
|📚 Категория|Теги книги|
|📖 Прочитано|Формат `23 / 200`|
|📈 Прогресс|Визуальный progress bar|
---
#### 🌡️ Прогресс-бар в действии
```js
const percent = Math.round((current / total) * 100);
const color = percent === 100 ? 'green' : 'orange';
```
- Вычисляется % прочитанного;
- Если дочитал до конца — зелёный;
- Если ещё читаешь — оранжевый.
Визуальный индикатор прямо в Obsidian — как в привычных трекерах.
---
#### 🎮 6. Добавляем "жизнь"
```js
select.onchange = () => renderTable(select.value, searchInput.value);
searchInput.oninput = () => renderTable(select.value, searchInput.value);
```
Когда пользователь меняет категорию или вводит запрос — таблица **перерисовывается** с учётом фильтров.
---
#### 🧩 Что тебе нужно для запуска
- Папка с заметками о книгах;
- В каждой заметке должен быть YAML с такими полями:
```yaml
cover: https://link.to/cover.jpg
Автор: Имя Автора
tags: [Продуктивность, Философия]
страница: 80
всего страниц: 200
```
---
### 💥 Что ты получаешь
- **Каталог книг с фильтрами и поиском**;
- Красивый визуал — обложки, прогресс, категории;
- Работает **прямо в Obsidian**, без внешних сервисов.