Skip to content

Instantly share code, notes, and snippets.

@alexey-goloburdin
Last active April 22, 2025 18:21
Show Gist options
  • Save alexey-goloburdin/48a1075a7654c19ebd9641be5e4432fb to your computer and use it in GitHub Desktop.
Save alexey-goloburdin/48a1075a7654c19ebd9641be5e4432fb to your computer and use it in GitHub Desktop.
/* .obsidian/snippets/snippet.css */
/* Base settings for all page width */
.wide-100 .cm-contentContainer, .wide-100 .cm-content, .wide-100 .cm-line,
.wide .cm-contentContainer, .wide .cm-content, .wide .cm-line,
.wide-95 .cm-contentContainer, .wide-95 .cm-content, .wide-95 .cm-line,
.wide-90 .cm-contentContainer, .wide-90 .cm-content, .wide-90 .cm-line,
.wide-85 .cm-contentContainer, .wide-85 .cm-content, .wide-85 .cm-line,
.wide-80 .cm-contentContainer, .wide-80 .cm-content, .wide-80 .cm-line,
.wide-75 .cm-contentContainer, .wide-75 .cm-content, .wide-75 .cm-line,
.wide-70 .cm-contentContainer, .wide-70 .cm-content, .wide-70 .cm-line,
.wide-65 .cm-contentContainer, .wide-65 .cm-content, .wide-65 .cm-line,
.wide-60 .cm-contentContainer, .wide-60 .cm-content, .wide-60 .cm-line,
.wide-55 .cm-contentContainer, .wide-55 .cm-content .wide-55 .cm-line
{
width: 100% !important;
max-width: 100% !important;
}
/* 100% page width for page with attribute cssclasses=wide-100 or cssclasses=wide */
.wide-100 .cm-sizer, .wide-100 .cm-contentContainer, .wide-100 .cm-content, .wide-100 .markdown-preview-sizer,
.wide .cm-sizer, .wide .cm-contentContainer, .wide .cm-content, .wide .markdown-preview-sizer
{
width: 100% !important;
max-width: 100% !important;
}
/* 95% page width for page with attribute cssclasses=wide-95 */
.wide-95 .cm-sizer, .wide-95 .markdown-preview-sizer {
width: 95% !important;
max-width: 95% !important;
}
/* 90% page width for page with attribute cssclasses=wide-90 */
.wide-90 .cm-sizer, .wide-90 .markdown-preview-sizer {
width: 90% !important;
max-width: 90% !important;
}
/* 85% page width for page with attribute cssclasses=wide-85 */
.wide-85 .cm-sizer, .wide-85 .markdown-preview-sizer {
width: 85% !important;
max-width: 85% !important;
}
/* 80% page width for page with attribute cssclasses=wide-80 */
.wide-80 .cm-sizer, .wide-80 .markdown-preview-sizer {
width: 80% !important;
max-width: 80% !important;
}
/* 75% page width for page with attribute cssclasses=wide-75 */
.wide-75 .cm-sizer, .wide-75 .markdown-preview-sizer {
width: 75% !important;
max-width: 75% !important;
}
/* 70% page width for page with attribute cssclasses=wide-70 */
.wide-70 .cm-sizer, .wide-70 .markdown-preview-sizer {
width: 70% !important;
max-width: 70% !important;
}
/* 65% page width for page with attribute cssclasses=wide-65 */
.wide-65 .cm-sizer, .wide-65 .markdown-preview-sizer {
width: 65% !important;
max-width: 65% !important;
}
/* 60% page width for page with attribute cssclasses=wide-60 */
.wide-60 .cm-sizer, .wide-60 .markdown-preview-sizer {
width: 60% !important;
max-width: 60% !important;
}
/* 55% page width for page with attribute cssclasses=wide-55 */
.wide-55 .cm-sizer, .wide-55 .markdown-preview-sizer {
width: 55% !important;
max-width: 55% !important;
}
/* Cosmetics for metadata and code blocks */
.cm-preview-code-block:hover {
box-shadow: none !important;
}
.metadata-properties-title {color: #d5d5d5; content:"Свойства";}
.metadata-properties-heading .collapse-indicator {display: none;}
/* Books render classes */
.books > span {
padding: 15px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
grid-auto-rows: minmax(300px, auto);
gap: 10px;
height: 100%;
}
.books img {
cursor: pointer;
height: 250px !important;
display: block;
margin: 0 auto 10px auto;
}
.books p[dir=auto] {margin: 0;}
.books progress {display: block !important; margin: 0 auto;}
.books .book {text-align: center;}
.books .book .pages {color: #9e9e9e; font-size: 0.75em;}
.books .book .category {
display: inline-block;
margin-bottom: 0.3em;
background-color: #f7efc3;
border-radius: 3px;
padding: 0px 7px;
width: auto;
font-size: 0.75em;
}
---
cssclasses:
- wide-85
---
# Читаю сейчас (`$= dv.pages("").where(page => {if (page["Тип"] && page["Тип"].path == "types/Книга.md" && page.file.folder != "templates" && !page["Закончил читать"] && page["Начал читать"]) {return page;}}).length`)
```dataviewjs
const categoryColors = {
"эффективность": "#fff9f2", "разработка": "#ebffff", "edtech": "#f5fff7",
"съёмка": "#f7f9ff", "художественное": "#fffdf0",
"default": "#f5f5f5"
};
const getCategoryColor = category => {
if (category in categoryColors) return categoryColors[category];
else return categoryColors["default"];
}
const getBooks = () => dv.pages("").where(page => {
if (page["Тип"] && page["Тип"].path == "types/Книга.md" && page.file.folder != "templates" && !page["Закончил читать"] && page["Начал читать"]) {
return page;
}
}).sort(p => p["Начал читать"], "desc");
const formatDate = d => {
return d.year === dv.date("now").year
? d.toFormat("d MMMM", { locale: "ru" })
: d.toFormat("d MMMM yyyy", { locale: "ru" });
}
let books = [];
for (const book of getBooks()) {
const categories = book.Категории.map(
c => `<span class="category" style="background-color: ${getCategoryColor(c)}">${c}</span>`
).join(" ");
books.push(`<div class="book">
<a data-tooltip-position="top" data-href="${book.file.name}" href="${book.file.name}.md" class="internal-link" target="_blank" rel="noopener nofollow"><img src="${book.Обложка}" data-filename="${book.file.name}" /></a>
${book.Progress}
начал ${formatDate(book["Начал читать"])}<br>
<div class="categories">${categories}</div>
<div class="pages">${book.Страниц} стр.</div>
</div>`);
}
dv.el("div", books.join(""), {cls: "books"});
```
# Читаю сейчас
```dataviewjs
let booksCount = 0;
let bookPages = dv.pages("").where(page => {
if (page["Тип"] && page["Тип"].path == "types/Книга.md" && page.file.folder != "templates" && !page["Закончил читать"] && page["Начал читать"]) {
booksCount++;
return page;
}
}).sort(p => p["Начал читать"], "desc");
const MAX_BOOK_NAME_LENGTH = 50;
let index = booksCount + 1;
dv.table(
["", "Название", "Автор", "Страниц", "Начал", "Прогресс"],
bookPages.map(p => {
const shortName = p.Название.length > MAX_BOOK_NAME_LENGTH
? p.Название.substring(0, MAX_BOOK_NAME_LENGTH) + "..."
: p.Название;
const authors = p.Автор.split(",").map(el => el.trim()).join("<br />");
return [
--index,
dv.fileLink(p.file.path, false, shortName),
authors,
p.Страниц,
p["Начал читать"] !== null ? p["Начал читать"] :
"",
p.Progress
];
})
);
```
# Прочитанное в 2025
```dataviewjs
let booksCount = 0;
let bookPages = dv.pages("").where(page => {
if (page["Тип"] && page["Тип"].path == "types/Книга.md" && page.file.folder != "templates" && page["Закончил читать"] && new Date(page["Закончил читать"].ts).getFullYear() === 2025) {
booksCount++;
return page;
}
}).sort(p => p["Закончил читать"], "desc");
const MAX_BOOK_NAME_LENGTH = 50;
let index = booksCount + 1;
dv.table(
["", "Название", "Автор", "Страниц", "Прочитал"],
bookPages.map(p => {
const shortName = p.Название.length > MAX_BOOK_NAME_LENGTH
? p.Название.substring(0, MAX_BOOK_NAME_LENGTH) + "..."
: p.Название;
const authors = p.Автор.split(",").map(el => el.trim()).join("<br />");
return [
--index,
dv.fileLink(p.file.path, false, shortName),
authors,
p.Страниц,
p["Закончил читать"] !== null ? p["Закончил читать"] :
""
];
})
);
```
# Все книги
```dataviewjs
let booksCount = 0;
let book_pages = dv.pages("").where(page => {
if (page["Тип"] && page["Тип"].path == "types/Книга.md" && page.file.folder != "templates") {
booksCount++;
return page;
}
}).sort(p => p["Закончил читать"], "desc");
const MAX_BOOK_NAME_LENGTH = 50;
let index = booksCount + 1;
dv.table(
["", "Название", "Автор", "Страниц", "Прочитана"],
book_pages.map(p => {
const shortName = p.Название.length > MAX_BOOK_NAME_LENGTH
? p.Название.substring(0, MAX_BOOK_NAME_LENGTH) + "..."
: p.Название;
const authors = p.Автор.split(",").map(el => el.trim()).join("<br />");
return [
--index,
dv.fileLink(p.file.path, false, shortName),
authors,
p.Страниц,
p["Закончил читать"] !== null ? p["Закончил читать"] :
""
];
})
);
```
@Aniome
Copy link

Aniome commented Apr 4, 2025

Если кому-то, как и мне надо сделать поиск книг прямо в заметке, то вот готовый код:

const categoryColors = {
	"эффективность": "#fff9f2", "разработка": "#ebffff", "edtech": "#f5fff7",
	"съёмка": "#f7f9ff", "художественное": "#fffdf0",
	"default": "#f5f5f5"
};
const getCategoryColor = category => {
    if (category in categoryColors) return categoryColors[category];
    else return categoryColors["default"];
}

const getBooks = () => dv.pages("").where(page => {
    if (page["Тип"] && page["Тип"].path == "types/Книга.md" && page.file.folder != "templates" && !page["Закончил читать"] && page["Начал читать"]) {
      return page;
    }
}).sort(p => p["Начал читать"], "desc");

const formatDate = d => {
    return d.year === dv.date("now").year
        ? d.toFormat("d MMMM", { locale: "ru" })
        : d.toFormat("d MMMM yyyy", { locale: "ru" });
}

const filterBooks = (books, searchQuery) => {
    if (!searchQuery) return books;
    const query = searchQuery.toLowerCase();
    return books.filter(book => {
        const title = book.file.name.toLowerCase();
        const categories = book.Категории?.join(" ").toLowerCase() || "";
        const author = book.Автор?.toLowerCase() || "";
        return title.includes(query) || 
               categories.includes(query) || 
               author.includes(query);
    });
};

// Создаем поле для поиска
const searchInput = dv.el("input", "", {
    attr: {
        type: "text",
        placeholder: "🔍 Поиск по названию, категориям или автору...",
        style: "width: 100%; padding: 8px; margin-bottom: 20px; border: 1px solid var(--background-modifier-border); border-radius: 4px;"
    }
});

// Обработчик ввода (динамическая фильтрация)
let searchQuery = "";
searchInput.oninput = (e) => {
    searchQuery = e.target.value;
    renderBooks();
};

const renderBooks = () => {
	const filteredBooks = filterBooks(getBooks(), searchQuery);
	let books = "";

	for (const book of filteredBooks) {
		const categories = book.Категории.map(
		    c => `<span class="category" style="background-color: ${getCategoryColor(c)}">${c}</span>`
		).join(" ");
	    books += `<div class="book">
			<a data-tooltip-position="top" data-href="${book.file.name}" href="${book.file.name}.md" class="internal-link" target="_blank" rel="noopener nofollow"><img src="${book.Обложка}" data-filename="${book.file.name}" /></a>
	        ${book.Progress}
	        начал ${formatDate(book["Начал читать"])}<br>
	        <div class="categories">${categories}</div>
	        <div class="pages">${book.Страниц} стр.</div>
	    </div>`;
	}

	const booksContainer = dv.container.querySelector("div.books");
	if (booksContainer) {
		const span = booksContainer.firstElementChild;
		span.innerHTML = books || "<p>Ничего не найдено.</p>";
	} else {
		dv.el("div", books, {cls: "books"});
	}
};

renderBooks();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment