## 📊 Статистика ```dataviewjs const books = dv.pages('"Библиотека/Книги"').where(p => p.Тип == "Книга"); const read = books.where(p => p.Статус == "Прочитано"); const inProgress = books.where(p => p.Статус == "В процессе"); const planned = books.where(p => p.Статус == "Хочу прочитать" || p.Статус == "Запланировано"); const abandoned = books.where(p => p.Статус == "Заброшена"); const totalPages = read.array().reduce((sum, p) => sum + (Number(p["Количество страниц"]) || 0), 0); const rated = read.where(p => p.Оценка); const avgRating = rated.length ? (rated.array().reduce((s, p) => s + Number(p.Оценка), 0) / rated.length).toFixed(1) : "—"; dv.table(["", ""], [ ["📚 Всего книг", books.length], ["✅ Прочитано", read.length], ["📖 Читаю сейчас", inProgress.length], ["🔖 Хочу прочитать", planned.length], ["⛔ Заброшено", abandoned.length], ["📄 Страниц прочитано", totalPages.toLocaleString("ru-RU")], ["⭐ Средняя оценка", avgRating], ]); ``` --- ```dataviewjs const books = dv.pages('"Библиотека/Книги"') .where(p => p.Тип == "Книга" && p.Статус == "В процессе"); if (!books.length) { dv.paragraph("*Сейчас ничего не читаю*"); } else { dv.table(["Обложка", "Название", "Автор", "Прогресс", "Страниц"], books.map(p => { const total = Number(p["Количество страниц"]) || 0; const done = Number(p.Прогресс) || 0; const pct = total ? Math.round(done / total * 100) : 0; const filled = Math.round(pct / 10); const bar = "█".repeat(filled) + "░".repeat(10 - filled); return [ p.Обложка ? dv.span(`![|75](${p.Обложка})`) : "—", p.file.link, p.Автор ? [].concat(p.Автор).join(", ") : "—", `\`${bar}\` ${pct}%`, `${done} / ${total}` ]; }) ); } const details = document.createElement("details"); details.setAttribute("open", ""); const summary = document.createElement("summary"); summary.innerHTML = `📖 Читаю сейчас (${books.length})`; details.appendChild(summary); Array.from(this.container.childNodes).forEach(n => details.appendChild(n)); this.container.appendChild(details); ``` --- ```dataviewjs const fmt = f => ({ "Электронная": "📱", "Бумажная": "📗", "Аудио": "🎧" }[f] ?? ""); const books = dv.pages('"Библиотека/Книги"') .where(p => p.Тип == "Книга" && (p.Статус == "Хочу прочитать" || p.Статус == "Запланировано")) .sort(p => p.Название, "asc"); dv.table(["Обложка", "Название", "Автор", "Страниц", "Формат", "Категория"], books.map(p => [ p.Обложка ? dv.span(`![|75](${p.Обложка})`) : "—", p.file.link, p.Автор ? [].concat(p.Автор).join(", ") : "—", p["Количество страниц"] || "—", fmt(p.Формат), p.Категории ? [].concat(p.Категории).join(", ") : "—" ]) ); const details = document.createElement("details"); const summary = document.createElement("summary"); summary.innerHTML = `🔖 Хочу прочитать (${books.length})`; details.appendChild(summary); Array.from(this.container.childNodes).forEach(n => details.appendChild(n)); this.container.appendChild(details); ``` --- ```dataviewjs const star = n => n ? `⭐ ${Number(n)}` : "—"; const fmt = f => ({ "Электронная": "📱", "Бумажная": "📗", "Аудио": "🎧" }[f] ?? f ?? "—"); const books = dv.pages('"Библиотека/Книги"') .where(p => p.Тип == "Книга" && p.Статус == "Прочитано") .sort(p => Number(p.Закончена) || 0, "desc"); dv.table(["Обложка", "Название", "Автор", "Год", "Оценка", "Формат", "Категория"], books.map(p => [ p.Обложка ? dv.span(`![|75](${p.Обложка})`) : "—", p.file.link, p.Автор ? [].concat(p.Автор).join(", ") : "—", p.Закончена || "—", star(p.Оценка), fmt(p.Формат), p.Категории ? [].concat(p.Категории).join(", ") : "—" ]) ); const details = document.createElement("details"); const summary = document.createElement("summary"); summary.innerHTML = `✅ Прочитано (${books.length})`; details.appendChild(summary); Array.from(this.container.childNodes).forEach(n => details.appendChild(n)); this.container.appendChild(details); ``` --- ```dataviewjs const books = dv.pages('"Библиотека/Книги"') .where(p => p.Тип == "Книга" && p.Статус == "Заброшена"); if (!books.length) { dv.paragraph("*Нет заброшенных книг*"); } else { dv.table(["Название", "Автор", "Прочитано страниц"], books.map(p => [ p.file.link, p.Автор ? [].concat(p.Автор).join(", ") : "—", p.Прогресс || "—" ]) ); } const details = document.createElement("details"); const summary = document.createElement("summary"); summary.innerHTML = `⛔ Заброшено (${books.length})`; details.appendChild(summary); Array.from(this.container.childNodes).forEach(n => details.appendChild(n)); this.container.appendChild(details); ```