Obsidian + Dataview: Таблицы

1ca85bf6ea63d47593cb92768fa41628.png

На статью меня вдохновил этот комментарий .

Dataview — это мощный плагин для Obsidian позволяющий отбирать данные (теги, даты, числа и любые другие пользовательские параметры) markdown-заметок, а затем их фильтровать и отбирать как пожелаешь.

Это такой своеобразный аналог Notion-таблиц, где можно создать таблицу с бесконечной вложенностью (таблица, внутри одной ячейки, а внутри еще таблица и еще и еще).

На КДПВ как раз собраны разные кейсы реализации функционала плагина Dataview:

  1. Книги с прогрессом чтения

  2. Проекты со счётчиком выполненных и не выполненных задач

  3. Прогресс года, месяца, дня и всей жизни

  4. Фильмы в виде карточек Разбирать каждый кейс я буду под катом.

Установка Dataview

  1. Данная инструкция написана для версии программы 1.1.9. (Перед всеми нижеописанными действиями надо неплохо было бы обновиться: Меню => О программе => Проверить обновления)

    231efdc0b3fddf2c3fa2f6f3d884d31b.png
  2. Для начала идём в Меню => Сторонние плагины => Включите плагины сообщества

    dc2ecba09b85fe11769799c7c8c3ecf7.png
  3. Затем «Обзор»

    758082ba770d26c2f9417197ae92e1d2.png
  4. Затем находим в списке Dataview (Можно написать в поиске, а можно не писать, данный плагин находится вторым в списке)

    86589f57ed739aa6a54ea7865d729ee8.png
  5. Жмём «Установить», ждём пару секуд пока плагин скачается и установится

    bd55caf0bb3f6aa0f251090eee8cb752.png
  6. Затем жмём «Включить»

    6bf7fe94e0facbddc973aa31542bbdf2.png

    Как всё это работает в двух словах

    1. Dataview работает на встроенном языке запросов

    2. Все запросы должны писаться внутри подобного блока кода:

    ```dataview
    TABLE|LIST|TASK <Поле1> [AS "Название столбца"], <Поле2>, ..., <Поле3> 
    FROM <Источник>
    WHERE <Выражение>
    SORT <Выражение> [ASC/DESC]
    ... другие команды
    ```

Книги с прогрессом чтения

  1. Данный кейс предназначен для составления своей базы данных книг и отслеживания прогресса чтения

  2. Код запроса выглядит так:

```dataview
TABLE WITHOUT ID 
	file.link AS "Книга",
	Прогресс_Бар AS "Прогресс",
	Автор,
	URL
FROM "Книги"
```
  1. Разбираем код построчно:

    1. TABLE WITHOUT ID — мы указали, что нам нужна таблица

    2. Далее перечисляем столбцы, которые нам нужны, первым столбцом будет ссылка на саму заметку (file.link), а называться этот столбец будет «Книга» (AS Книга)

    3. Затем нам нужен прогресс бар (Прогресс_Бар), а называться этот столбец будет «Прогресс» (AS «Прогресс») — AS … — мы пишем только тогда, когда хотим, чтобы столбец назывался как-то отлично от параметра, который за ним скрывается. Для разнообразия можно использовать эмодзи, они поддерживаются.

    4. Затем Автор

    5. Затем URL

    6. Затем мы указываем откуда будут собираться и обрабатываться заметки из папки «Книги» (FROM «Книги»). Данный способ отбора заметок подходит для тех, кто хочет отобрать заметки из определённой папки => в вашем хранилище заметки должны быть рассортированы по папкам. В дальнейшем при добавленнии в указанную папку новой заметки она так же отобразится в получившейся таблице.

  2. Сами заметки должны лежать в папке «Книги» и содержать следующий набор параметров:

URL:: [LitRes](https://www.litres.ru/stiven-kovi/7-navykov-vysokoeffektivnyh-ludey-moschnye-instrumenty-razviti/)
Автор:: "Кови Стивен"
Прогресс_Бар:: 

90%

  1. Разбираем построчно:

    1. Название заметки — Оно отобразится в таблице первым

    2. URL — это ссылка на книгу

    3. Автор — Это автор книги в ковычках, т.к. есть пробел

    4. Прогресс_Бар — Тут мы задаём параметры прогресс бара, максимальное значение (progress max=100), текущее значение (value=90) и текстовое пояснение (90%)

  2. В конечном итоге получается вот такая таблица:

    baa3d2c4b49672b0bcfc171ef03a4163.png

Проекты со счётчиком выполненных и не выполненных задач

  1. Данный кейс предназначен для отслеживания прогресса по проектам

  2. Код запроса выглядит вот так:

```dataview
TABLE WITHOUT ID 
	file.link AS Проект,
	Статус,
	(length(filter(file.tasks.completed, (t) => t = true))) / (length(file.tasks.text)) * 100 AS "% Завершено",
	(length(file.tasks.text)) AS Всего,
	(length(filter(file.tasks.completed, (t) => t = true))) AS Завершённых,
	(length(file.tasks.text)) - (length(filter(file.tasks.completed, (t) => t = true))) AS "Незавршенных"
FROM #проекты
```
  1. Разбираем код построчно:

    1. TABLE WITHOUT ID — мы указали, что нам нужна таблица

    2. Далее перечисляем столбцы, которые нам нужны, первым столбцом будет ссылка на саму заметку (file.link), а называться этот столбец будет «Проект» (AS Проект)

    3. Статус — это статус наших проектов (В процессе, Готово, Не приступал)

    4. Следующей строчкой мы вычисляем кол-во завершённых задач проекте и кол-во незавершённых задач, делим их друг на друга и получаем процент готовности проекта

    5. Данной строчкой мы считаем кол-во всех задач, т.е. берём размер массива file.tasks.text

    6. Этой строчкой мы считаем кол-во завершённых задач

    7. А этой строчкой мы вычитаем из общего кол-ва задач кол-во завершённых задач и таким образом получаем кол-во незавершённых задач

    8. Затем мы указываем откуда будут собираться и обрабатываться заметки. В данном случае будут отбираться все заметки с тегом #проекты (FROM #проекты). Данный способ отбора заметок подходит для тех, кто хочет отобрать заметки с определённым тего => в вашем хранилище заметкам должны быть присвоены соответствующе теги. В дальнейшем при добавленнии в хранилище новой заметки с указанным тегом она так же отобразится в получившейся таблице.

  2. Сами заметки должны содержать следующий набор параметров:

#проекты
Статус:: "Готово"

---
# ToDo:
- [x] Снять размеры с вытяжки
- [x] Нагуглить вытяжки
- [x] Купить вытяжку
- [x] Съездить за вытяжкой в магазин
- [x] Установить вытяжку
  1. Разбираем построчно:

    1. Тег #проекты — чтобы запрос отбирал нужную нам заметки

    2. Статус — чтобы он отображался в таблице. В дальнейшем этот статус можно будет менять в заметке и он будет меняться в таблице

    3. Затем разделитель (---) — для удобства

    4. И затем список задач — которые будут обрабатываться нашей таблицей

  2. В конечном итоге получаем вот такую таблицу:

Прогресс года, месяца, дня и всей жизни

  1. Данный кейс предназначен для наглядной визуализации прошедшего года\месяца\дня\жизни. Нужен этот блок для грусти о потерянном времени

  2. Код запроса выглядит побольше, вот так (в данном коде используется уже JavaScript). Отличается он первой строчкой dataview => dataviewjs

```dataviewjs
const today = DateTime.now()
const endOfYear = {
    year: today.year,
    month: 12,
    day: 31
}

const lifespan = { year: 80 } 
const birthday = DateTime.fromObject({
    year: 1990,
    month: 3,
    day: 11
});
const deathday = birthday.plus(lifespan)

function progress(type) {
    let value;
    
    switch(type) {
        case "lifespan": 
            value = (today.year - birthday.year) / lifespan.year * 100;
            break;
        case "year":
            value = today.month / 12 * 100
            break;
        case "month":
            value = today.day / today.daysInMonth * 100
            break;
        case "day":
            value = today.hour / 24 * 100
            break;
    }
    return ` | ${parseInt(value)} %`
}


dv.span(`
|  | Прогресс  | Процент |
| --- | --- |:---:|
| **Год** | ${progress("year")}
| **Месяц**| ${progress("month")}
| **День**| ${progress("day")}
| **Жизнь** | ${progress("lifespan")}
`)
```
  1. Разбираем код построчно:

    1. В первом блоке мы задаём константы текущего дня и конца года

    2. Во втором блоке мы задаём прогнозируемую продолжительность жизни (80 лет) и дату рождения

    3. Далее описываем функцию расчёта прогресса

    4. И в конце представляем всё это в виде произвольной markdown таблицы

  2. В конечном итоге получаем вот такую таблицу:

    56d104ebcd65639882c3b1a2fe2e9e3b.png

Фильмы в виде карточек

  1. Данный кейс предназначен для составлении своей библиотеки просмотренных или наоборот непросмотренных фильмов. Для реализации данного кейса необходимо сделать еще пару приготовительных действий:

    1. Сначала ставим тему Minimal, для этого идём в настройки => Оформление => Настроить

      2200817d18d55685ceab0541ec4ef746.png
    2. Там выбираем тему Minimal

      2612c4981e948de235ef7464473f842d.png
    3. Затем идём в сторонние плагины и устанавливаем и включаем плагин Minimal Theme Settings

      06c85b4da714a23fc3bf519075618e71.png
    4. А затем так же устанавливаем плагин Sortable

      cd7e2d8e1319672ee78dd58aafa9301c.png
  2. Код запроса выглядит вот так:

---
cssClasses: cards, cards-cover, cards-1-1, table-max, cards-cols-4
---

```dataview
TABLE WITHOUT ID 
	("![](" + Постер + ")") as Постер,
	file.link AS Название,
	Год,
	РейтингКП,
	URL
FROM "Фильмы"
```
  1. Разбираем построчно:

    1. Сначала мы присваиваем заметке кастомный css-класс, для этого отбиваем его сверху и снизу разделителями (---), а в между ними пишем cards, cards-cover, cards-1–1, table-max, cards-cols-4, это означает, что у нас будет таблица в виде карточек, карточки будут размером 1к1, таблица будет растянута на всю ширину заметки и фиксируем кол-во столбцов = 4

    2. Затем в блоке dataview мы опять задаём, что это будет таблица (TABLE WITHOUT ID)

    3. Затем вот такой строчкой ((»![](» + Постер + »)») as Постер) мы говорим обработчику, что хотим выводить сам постер в виде картинки в таблице

    4. Затем опять название заметки

    5. Затем год фильмы

    6. Затем рейтинг кинопоиска

    7. Затем выводим ссылку на кинопоиск

    8. Всё это мы собираем из папки «Фильмы» (FROM «Фильмы»)

  2. Сами заметки должны содержать следующий набор параметров:

Год:: 2003
РейтингКП:: 8.7
URL:: "[Кинопоиск](https://www.kinopoisk.ru/film/3498/)"
Постер:: "https://kinopoisk-ru.clstorage.net/N30iW1384/e515deON/2zI0YN6s508t2KHYsS6u_7YQb9WcfzvbzhmPOPlra6c20ffu3qRaZAQJo-WDAweGjJX5SdfmSPBis5fUXmnHbD_2FBHL6RZb6C10PEDu_jqzJI4VGWvvD0t9zunMvt5VxdN0zEmGOZaGC2Xxt0d2U1kADUiCU8zA4yem43291-vIU5VSn680az8ach9wPy7fZlK7xZ2-Lnivelnaa0qJ5yVh9D6bVHvkpSk0EiVWs5LrI69psdIegdcGtOBfS4VYifM08o7fBpqtOFJNMx2czWVQ-gQPLI5bTeoa6RpoiiVEcYa9yffYJCRZJ8Pnl3KCu6BsmxIzPMFmhOYQfDuH6kkB9lDufrQq7UigbmAeXU2WgRol7twNG-6467j669s1J4MEjBhnutWEaJVQBnVDsctDfQsBAs3AN4b0or9qp9gZ43bQ3M71GV6bYd5ArgwMxoG6lj69fVlvahtJenkoFHchBm3p98pVRml0IaZWIYLLEiwYEwIu0tTGRcGdSoY5yFE2ke7u52uNaoNPAKwNb0cha-YObg147FvZyDlo6vT08xT_OtaJJkfbFSHndNCR-xOfq-Hz3ZCm5abxLcq1ixqD9sLdj9f43iuCTED8jU-XM6v3nw18eax6CLtbSboll7BErsk0OjU2aLYxp1Ugg0rDThngYMzS10RGMJz5FTiJgjcynN6nCf34Uv8xrk8NBFLpJ9x83YotStvJW1lL9zQzlhyYZCqXFFtHkeR2EuCokG1asnH_kfeHxYAvaPb5qcN0oV3v9hnuK4BNcx6NbWTDynYsPi45PvnquMipSvUFYMRt-ffaZ7U7trA2tBMyifOvyIITLMHUVDSyfWmWWogBJrH_3ZTI_8vBjyOcbV_FQytnDo3dW-_LarppaStFNDNFThvmq9SG29RBhQZQINrCjfvR4D0T14WHIC9a9NgbQvXgj76GGv06IkzSnb9f1RF7dE2PDjjtK6s4aKq4NBdC5Y0LZqkmVUpVgNc0cRGJA6_r8rGP0AeGVoHfCWf6SgEH4o5tNlv-iNLcEe5tLpdzaWX9HP1JLWqb2evo-bRUwzZvyGS7F0bpxdBXNXBQe2Fv-oGx70FFVxagLxj1yBmiZGD9jqVJHWpCDNL_3byEEot1rz1eat0KuojJOhpGhuJGTUlUahcUCVax9heCcdlhf4ricg7C1YSmI91K5UnJA4Qh7a7l6S_6MB1g_q4vNnLZlvz-P5r8qCj5Gpm5FMcCRq8YhdqWpjj3k1REEiJ7YG0K4aPu0tf3J_KuypQaidBWgKxshwl_G9Od0R4PLUaS-pcuPf05P9oKSqk5SUcUUDaem_a4xsdqxWAndLIzmbCPC6ITDMBEx7bTH9mXy6sBdtEd7edabXhAbIMvHoy0M3g2Pg7ce30IGQsY2ugXVEJF7qjk-ndlGrUztCcx0vuyr4iB8s6CFGSV8-5bhStqsiYT_o1GyQ26Y56Djv7-dQJLBZ8938ie28vbe8rbhNWyBv97N8qVVrj1IcW2wjGKMB_pUrAfkPTllxJMy2Taq_J0ApzNFyj_udIM876c75fTy9VNLe1Z3GhZCHtbmcSkg4QNeQR6F3To56IWtyCR2DINmQMATnH3dAdRD3qEKZgQReK9nbbpfgpCz2GPHRxmcEinP13uCD6o2mnrucjXlQPkrNtUaacGy6Uj9CbR0xkzvOrh0Y2RJff18P741OhrMDTR_qzG-x1oAhyg_x5u52C4Vn0_34lcyvtJeNnL95dDB9zo5BnkZ_jWcrZG4IK60U9rYCJeUQbVhVGNS7XZGzP10g8_Zjm9KhD8MTxsLbahKlZvjr3L3PmIyKto2lWmQBT-KieploQZVfJUpzDA6DAcy8Mw_aJndGaC3opGG-nA19DPPkVpDUtz7KL-7nzn01g0Tv4euIxqS9jquvlm52PWf_t16zSna1cClydiwvnDraviknzDZTak8l5bdYprA-UBHP1X676LQj6gzYzdpMKpVYyOnKlemkn4OOjLRBRwJ33LJGjlF_kX0PZWMIPY4a8aEyPtMPU2lXMsW2fZenNHUe6uhgqvK5PNUIxOzWfjORbub35IvWmaajnLKYUVcaeuSwQLlZYIx6KGJBHxC7BfyiHQXTAVteVCTNpG6WozpuCuH2UZX2pQ3zLNHu1XEwmVrQyMGd44C4g5iUl05sMlfOpni7aFGSUB93cA0rliTZuT4c8gtZZ2o-5aliirYSaD3g5E6d8aMH7yHO8f5iBLxR5v3etPemvai5n615eiZcx6NguGtxkUIDVVUuPYAE-rsCJuYjbX5PBea6VZiAAUEQ7dVgqOanF-wo3O_7aBmncMr98ZXChImtq5O_bE88WtGgf49Aa61_O1JQPDiUK_moCz3KH3VAYQX9sFaHsDdKCvjYYYvfiR_mId_MylMntmP0yNSW7paMq5KXpmttPXfTomKTSWmceT9tUC89kAHXuxw33C1IQ3cv0K9ipKMCYzHy0War9KkPwyDgxNZXGIR-6cL4mOudvYaxgp9tWzJ9355KpmZlr0MHc3E-FZ4qzYEcPPMJb3J8JNeLbqS_OWoc8vNMvviCFNQ8wevbcBG-b-TD9Z3utLiWhbG-U04aQ-eFb7FSUJNIHGVaPTGdBcOOOyfcN0RlXibRuGKqtD5_KOf9drHRjyLgGt3gzH44l0fh5uWLx5y4kbafp3dINWrxvWCbR0aWVgNXeCIsnA3LuisS5S52Y3gcxZtUmpQAXhb-9WKJ6oAK5jnn-cpJN6p_0-3-veK2nLe1iIdBYCVp_6teqElVtFMhe3MlG7Us8KguINsweG9WMOa-RZe-E0YL-91JscGJF8Yn2uXuRxOUZePs5ZLtiJaOlJ6AUXUya_yfRKBlYq12HkxIHRCQCt-bAwTxFG9rbh_GiGC5tjZdF8PUcqr7phTvI8_z_kgzmULB9tOWyoiZoZycpHd1AGfvlk2mW3SKVgJIYTkNvCLOjTgT1ipvRX0"
  1. В конечном итоге получается вот такая таблица, которую можно на лету сортировать по любому из полей (благодаря плагину Sortable):

    a78bf679c2edd2cb4531061706e2996b.png

Заключение

Надеюсь я смог раскрыть маленькую частичку функционала плагина Dataview.
Возможно разобранные кейсы смогут кого-то вдохновить.

Не успев опубликовать эту статью, уже начал набрасывать статью про задачи в том же плагине Dataview, которые использую активно уже более года и к данному моменту создал уже более 6 тысяч задач себе.

А разбирать каждый кейс будем под катом.

© Habrahabr.ru