feat: перепиши кейс Card Columns без черновиков
This commit is contained in:
1 parent
d25c2e2185
commit
8b50c821a7
5 files changed
+387
-1396
No files matched your search
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Кейс: Card Columns, плагин-вид для Obsidian Bases. Показывает заметки как карточки, разложенные по колонкам, с фильтрацией тегов по И/ИЛИ."
|
||||
content="Как я создал Card Columns для Obsidian Bases: группировка заметок по свойствам, фильтрация тегов AND/OR и перенос карточек между колонками."
|
||||
/>
|
||||
<title>Card Columns, плагин для Obsidian Bases: кейс</title>
|
||||
<title>Card Columns для Obsidian Bases: кейс о канбан-виде</title>
|
||||
<script>
|
||||
(function () {
|
||||
var FONT_CSS = {
|
||||
@@ -112,20 +112,20 @@
|
||||
<meta property="og:site_name" content="Николай Мамадаев — продуктовый дизайнер" />
|
||||
<meta property="og:locale" content="ru_RU" />
|
||||
<meta property="og:locale:alternate" content="en_US" />
|
||||
<meta property="og:title" content="Card Columns, плагин для Obsidian Bases: кейс" />
|
||||
<meta property="og:description" content="Кейс: Card Columns, плагин-вид для Obsidian Bases. Показывает заметки как карточки, разложенные по колонкам, с фильтрацией тегов по И/ИЛИ." />
|
||||
<meta property="og:title" content="Card Columns для Obsidian Bases: кейс о канбан-виде" />
|
||||
<meta property="og:description" content="Как я создал Card Columns для Obsidian Bases: группировка заметок по свойствам, фильтрация тегов AND/OR и перенос карточек между колонками." />
|
||||
<meta property="og:url" content="https://mamadaevv.site/cases/card-columns-obsidian/" />
|
||||
<meta property="og:image" content="https://mamadaevv.site/assets/og/og-default.png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="Card Columns, плагин для Obsidian Bases: кейс" />
|
||||
<meta property="og:image:alt" content="Card Columns для Obsidian Bases: кейс о канбан-виде" />
|
||||
|
||||
<!-- Twitter / X -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Card Columns, плагин для Obsidian Bases: кейс" />
|
||||
<meta name="twitter:description" content="Кейс: Card Columns, плагин-вид для Obsidian Bases. Показывает заметки как карточки, разложенные по колонкам, с фильтрацией тегов по И/ИЛИ." />
|
||||
<meta name="twitter:title" content="Card Columns для Obsidian Bases: кейс о канбан-виде" />
|
||||
<meta name="twitter:description" content="Как я создал Card Columns для Obsidian Bases: группировка заметок по свойствам, фильтрация тегов AND/OR и перенос карточек между колонками." />
|
||||
<meta name="twitter:image" content="https://mamadaevv.site/assets/og/og-default.png" />
|
||||
<meta name="twitter:image:alt" content="Card Columns, плагин для Obsidian Bases: кейс" />
|
||||
<meta name="twitter:image:alt" content="Card Columns для Obsidian Bases: кейс о канбан-виде" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
@@ -169,8 +169,8 @@
|
||||
"@type": "CreativeWork",
|
||||
"@id": "https://mamadaevv.site/cases/card-columns-obsidian/#page",
|
||||
"url": "https://mamadaevv.site/cases/card-columns-obsidian/",
|
||||
"name": "Card Columns, плагин для Obsidian Bases: кейс",
|
||||
"description": "Кейс: Card Columns, плагин-вид для Obsidian Bases. Показывает заметки как карточки, разложенные по колонкам, с фильтрацией тегов по И/ИЛИ.",
|
||||
"name": "Card Columns для Obsidian Bases: кейс о канбан-виде",
|
||||
"description": "Как я создал Card Columns для Obsidian Bases: группировка заметок по свойствам, фильтрация тегов AND/OR и перенос карточек между колонками.",
|
||||
"isPartOf": {
|
||||
"@id": "https://mamadaevv.site/#website"
|
||||
},
|
||||
@@ -203,7 +203,7 @@
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 3,
|
||||
"name": "Card Columns, плагин для Obsidian Bases: кейс",
|
||||
"name": "Card Columns для Obsidian Bases: кейс о канбан-виде",
|
||||
"item": "https://mamadaevv.site/cases/card-columns-obsidian/"
|
||||
}
|
||||
]
|
||||
@@ -256,72 +256,7 @@
|
||||
.case-article a:not(.btn) {
|
||||
color: var(--accent);
|
||||
}
|
||||
.case-article .case-brief {
|
||||
list-style: none;
|
||||
margin: 1.5rem 0 0;
|
||||
padding: 1.1rem 1.25rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
|
||||
gap: 0.85rem 1.5rem;
|
||||
font-size: 0.9rem;
|
||||
border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
|
||||
border-radius: var(--radius-md, 12px);
|
||||
}
|
||||
.case-article .case-brief li {
|
||||
margin: 0;
|
||||
}
|
||||
.case-article .case-brief span {
|
||||
display: block;
|
||||
margin-bottom: 0.15rem;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.case-article .case-todo {
|
||||
margin: 1rem 0 1.25rem;
|
||||
padding: 0.9rem 1.1rem;
|
||||
border-left: 2px solid var(--accent);
|
||||
background: color-mix(in srgb, var(--accent) 8%, transparent);
|
||||
border-radius: 0 var(--radius-sm, 8px) var(--radius-sm, 8px) 0;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
.case-article .case-todo p {
|
||||
margin: 0 0 0.5rem;
|
||||
}
|
||||
.case-article .case-todo p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.case-article .case-todo__q {
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
}
|
||||
.case-todo__label {
|
||||
display: block;
|
||||
margin-bottom: 0.35rem;
|
||||
font-size: 0.68rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--accent);
|
||||
opacity: 0.85;
|
||||
}
|
||||
.case-article details.case-details {
|
||||
margin: 0.75rem 0 1rem;
|
||||
padding: 0.6rem 0.9rem;
|
||||
border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
|
||||
border-radius: var(--radius-sm, 8px);
|
||||
}
|
||||
.case-article details.case-details > summary {
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
.case-article details.case-details[open] > summary {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.case-block {
|
||||
margin-top: 3rem;
|
||||
padding-top: 2.5rem;
|
||||
@@ -492,311 +427,137 @@
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">Obsidian Bases · Plugin</p>
|
||||
<h1 class="case-page__h1">
|
||||
Канбан-вид для Obsidian Bases,<br />который не трогает ваши заметки
|
||||
Канбан-доска для Obsidian Bases<br />с фильтрацией и перетаскиванием
|
||||
</h1>
|
||||
<p class="case-page__sub">
|
||||
Card Columns: заметки как карточки по колонкам,<br />
|
||||
отбор по тегам И/ИЛИ за два клика
|
||||
Card Columns: группировка по свойствам,<br />
|
||||
быстрый отбор тегов AND/OR
|
||||
</p>
|
||||
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../../assets/card-columns-obsidian/overview.webp" alt="База ссылок в Obsidian, сгруппированная по тегам в колонки Card Columns" width="2084" height="1296" loading="eager" decoding="async" data-image-viewer />
|
||||
<figcaption>База заметок, сгруппированная по тегам в Columns</figcaption>
|
||||
<figcaption>Links: 196 результатов в режиме Columns</figcaption>
|
||||
</figure>
|
||||
|
||||
<ul class="case-brief">
|
||||
<li><span>Роль</span>Продуктовый дизайн и разработка</li>
|
||||
<li><span>Платформа</span>Obsidian Bases</li>
|
||||
<li><span>Статус</span>Рабочий плагин в <a href="https://community.obsidian.md/plugins/card-columns" target="_blank" rel="noopener noreferrer">каталоге плагинов Obsidian</a>, open source (MIT)</li>
|
||||
<li><span>Команда</span>Соло, пет-проект</li>
|
||||
<li><span>Срок</span>Черновой ответ, заменить</li>
|
||||
</ul>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<p class="case-todo__q">
|
||||
Сколько заняла работа от первой идеи до рабочей версии? Недели? Месяц выходных?
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: собрал за три недели вечером, потом ещё месяц доводил по ходу
|
||||
собственной работы. Заменить на реальное.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="section__prose">
|
||||
В Obsidian появились Bases, отдельный тип файла, который показывает заметки не текстом, а
|
||||
в разных видах: таблицей, карточками, деревом. Стандартный вид карточек мне не зашёл: он
|
||||
плоский, без группировки, и в нём не разобраться, когда заметок сотни. Я хотел видеть их
|
||||
раскладку по колонкам, как канбан, но без лишнего веса. Так появился плагин-вид Card Columns.
|
||||
Card Columns - мой плагин-вид для Obsidian Bases. Я спроектировал и разработал его сам:
|
||||
хотел видеть заметки колонками, а не искать нужные в длинной ленте штатного Cards. Плагин
|
||||
опубликован в <a href="https://community.obsidian.md/plugins/card-columns" target="_blank" rel="noopener noreferrer">каталоге Obsidian Community</a>,
|
||||
исходный код открыт по лицензии MIT.
|
||||
</p>
|
||||
|
||||
<div class="case-block" id="kontekst">
|
||||
<h2>Контекст</h2>
|
||||
<h2>От запроса Bases к колонкам</h2>
|
||||
<p class="section__prose">
|
||||
Bases, это не заметка и не отдельная база данных. Это запрос к vault-у: выбираешь
|
||||
заметки по фильтру, и фреймворк рисует их в выбранном виде. У самого Obsidian есть
|
||||
встроенный вид карточек, но он одноплановый: нет группировки по свойствам, нет
|
||||
нормальной фильтрации. Я решил сделать свой вид, который встраивается в переключатель
|
||||
Bases наравне со штатными.
|
||||
Файл <code>.base</code> описывает запрос к заметкам в vault: какие записи показать и какие
|
||||
свойства вывести. Штатный вид Cards в моей базе складывал результаты в длинную ленту.
|
||||
Я хотел видеть ту же выборку по группам, например по статусу или тегу.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Главное ограничение было в самом фреймворке: плагин не хранит данные, а рисует то, что
|
||||
выдал Bases-запрос (Sort, Filter, Properties, Search из тулбара). Значит, вся логика
|
||||
выборки остаётся на Bases, а моя задача, только представление и навигация по нему.
|
||||
Columns подключается как ещё один BasesView и получает результат запроса. Сортировка,
|
||||
фильтры, набор свойств и поиск остаются за штатным тулбаром. Я не стал заводить отдельную
|
||||
доску: заметки и настройки запроса остаются в Bases, плагин меняет только их представление.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="pochemu-svoi">
|
||||
<h2>Почему не готовое</h2>
|
||||
<div class="case-block" id="filtry">
|
||||
<h2>Сначала сгруппировать, потом отобрать</h2>
|
||||
<p class="section__prose">
|
||||
Прежде чем писать код, я посмотрел, что уже есть. Три пути, все мимо:
|
||||
Группировку настраиваю через Group by в тулбаре Bases: по тегу, статусу, категории или
|
||||
любому frontmatter-свойству. Если свойство не задано, Columns группирует по тегам. Колонки
|
||||
строятся из значений выбранного свойства, а исходный запрос остаётся тем же. Одна база
|
||||
подходит для разных разрезов: меняю только группировку.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<strong>Штатный вид карточек Bases.</strong> Рисует ровный поток карточек без группировки.
|
||||
Когда заметок за сотню, это лента, в которой нужно скроллить и вглядываться в заголовки.
|
||||
Отпал первым.
|
||||
Теги для быстрого отбора вынесены отдельными пилюлями под тулбаром. Щёлкнул один раз,
|
||||
оставил этот тег. Выбрал следующий, добавил его по OR. Для точного переключения использую
|
||||
Ctrl+клик или правую кнопку мыши, а кнопкой OR/AND меняю логику отбора:
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<strong>Канбан-плагины из комьюнити.</strong> Большинство тянет за собой свою систему
|
||||
хранения: доска живёт отдельно от vault-а, заметки дублируются. Получается вторая база,
|
||||
которую надо синхронизировать. Мне это было не нужно.
|
||||
Эти пилюли не заменяют Filter в тулбаре. Bases формирует исходную выборку, а теговый фильтр
|
||||
сужает её уже внутри Columns. Так я не меняю запрос, когда нужно быстро посмотреть подмножество.
|
||||
</p>
|
||||
<ul class="section__prose">
|
||||
<li>первый тег оставляет только заметки с ним;</li>
|
||||
<li>следующий добавляет заметки с любым из выбранных тегов;</li>
|
||||
<li>Ctrl+клик или правый клик добавляет и снимает один тег, не сбрасывая остальные;</li>
|
||||
<li>OR/AND переключает условие между «любой из» и «все выбранные», All очищает выбор.</li>
|
||||
</ul>
|
||||
<p class="section__prose">
|
||||
<strong>Соседний bases-kanban.</strong> Ближайший по духу: цепляется к Bases, делает
|
||||
канбан. Но он пишет в заметки: перетаскивание карточки меняет frontmatter. Для view-плагина
|
||||
это риск, о котором ниже.
|
||||
Фильтр остаётся перед глазами вместе с доской. Модальное окно здесь только мешало бы:
|
||||
пришлось бы закрывать его, чтобы проверить результат.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">📌</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
Отказ от drag-and-drop, это не недоделка, а позиция. Плагин представления не должен
|
||||
писать в пользовательские данные. Это решение определило всё остальное.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<p class="case-todo__q">
|
||||
Ты реально ставил и тестировал чужие плагины или ориентировался по описаниям? Какие
|
||||
именно смотрел?
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: поставил три штуки, погонял неделю на своей базе, удалил. bases-kanban
|
||||
смотрел в исходниках, не ставил. Заменить на реальное, названия плагинов вписать.
|
||||
</p>
|
||||
</div>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../../assets/card-columns-obsidian/filter-use.webp" alt="Теги-фильтры над колонками карточек Card Columns" width="1280" height="796" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Фильтры тегов остаются рядом с колонками</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="zadacha">
|
||||
<h2>Задача</h2>
|
||||
<div class="case-block" id="kartochki">
|
||||
<h2>Карточка показывает нужные поля</h2>
|
||||
<p class="section__prose">
|
||||
Спроектировать вид для Bases, который показывает заметки карточками по колонкам и позволяет
|
||||
быстро отбирать нужное. Жёсткое ограничение: плагин ничего не пишет в заметки и не хранит
|
||||
своего состояния, а сортировка, фильтр, свойства и поиск из штатного тулбара Bases должны
|
||||
работать как раньше.
|
||||
Состав карточки задаётся штатным списком Properties. Первое выбранное свойство становится
|
||||
заголовком, остальные отображаются чипами: текст, теги, ссылки, булевы значения и даты.
|
||||
Для чипов можно выбрать вертикальный стек или компактную сетку, настроить перенос и формат даты.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Если базе нужны обложки, Columns возьмёт первую картинку из заметки или значение указанного
|
||||
frontmatter-свойства. Можно настроить пропорции (Auto, 1:1, 3:2, 4:3 или 16:9), вписывание
|
||||
и место обложки. Карточка открывается в активной панели, модальном окне, новой вкладке или
|
||||
сплите. В сплите обычный клик переиспользует панель, Ctrl+клик открывает новую вкладку.
|
||||
Так можно читать заметку рядом с доской и не терять контекст выборки.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">📌</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
Главный риск, сделать вид, который конфликтует со штатным тулбаром Bases. Тогда
|
||||
пользователь теряет сортировку и поиск, ради которых Bases и берут. Этого нельзя
|
||||
было допустить.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="reshenie">
|
||||
<h2>Решения</h2>
|
||||
<h2>Перетаскивание меняет свойство заметки</h2>
|
||||
<p class="section__prose">
|
||||
Плагин добавляет в Bases вид «Columns». Карточки строятся из результатов Bases-запроса,
|
||||
группировка задаётся свойством, а отбор, кликабельными тегами. Дальше, пять выборов,
|
||||
которые определили результат. В каждом есть то, от чего я отказался.
|
||||
</p>
|
||||
<!-- МЕДИА: скриншот вида с колонками и карточками внутри.
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../assets/card-columns-obsidian/board.webp" alt="Колонки карточек с группировкой по свойству" width="1920" height="1080" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Вид с колонками</figcaption>
|
||||
</figure>
|
||||
-->
|
||||
|
||||
<h3>Группировка по любому свойству</h3>
|
||||
<p class="section__prose">
|
||||
Колонки формируются из Group by в тулбаре Bases, по тегу, статусу, категории или любому
|
||||
frontmatter-свойству. Меняешь свойство в запросе, и доска пересобирается сама. Так одна
|
||||
и та же база закрывает разные разрезы: проекты по статусу, заметки по тегам, задачи по
|
||||
приоритету.
|
||||
</p>
|
||||
|
||||
<h3>Фильтр тегов по И и ИЛИ</h3>
|
||||
<p class="section__prose">
|
||||
Это то, ради чего плагин и задумывался. Под тулбаром, пилюли тегов, по клику они
|
||||
отсеивают карточки по всем колонкам сразу:
|
||||
</p>
|
||||
<ul class="section__prose">
|
||||
<li>Левый клик по тегу, показать только его (сбрасывает остальные фильтры).</li>
|
||||
<li>Левый клик по следующему тегу, показать заметки с ЛЮБЫМ из выбранных (режим ИЛИ).</li>
|
||||
<li>Ctrl+Клик или правый клик, переключить тег, не сбрасывая выбор.</li>
|
||||
<li>Кнопка OR/AND, переключить между «любой из» и «все перечисленные» для нескольких тегов.</li>
|
||||
<li>All, снять все фильтры.</li>
|
||||
</ul>
|
||||
<p class="section__prose">
|
||||
Связка «ИЛИ-добавление левым кликом + точный toggle через Ctrl» получилась интуитивной:
|
||||
быстрый отбор не сбивает то, что уже выбрано. Альтернативу, вынести фильтр в модалку,
|
||||
отверг сразу: лишний клик и потеря контекста того, что уже отфильтровано.
|
||||
В релизе 0.9.0 карточку можно перетащить в другую колонку, и Columns обновит
|
||||
frontmatter-свойство, по которому построена группировка, через API
|
||||
Obsidian <code>processFrontMatter()</code>. Если колонки собраны по статусу, после переноса
|
||||
меняется именно статус заметки. Если в свойстве несколько значений, старое убирается,
|
||||
новое добавляется, остальные сохраняются.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Выбор здесь не в самой фиче, а в том, где она живёт. Я выбрал пилюли под тулбаром вместо
|
||||
отдельного окна фильтров, потому что отбор по тегам, это действие на каждом шаге работы
|
||||
с базой. Модалка превращает его в прерванный сценарий: открыл, настроил, закрыл, проверил.
|
||||
Пилюли оставляют результат перед глазами, а состояние фильтра видно всегда.
|
||||
Я оставил этот сценарий настраиваемым. Drag-and-drop включён по умолчанию, но его можно
|
||||
отключить в General. Так пользователь сам выбирает: только смотреть на группы или менять
|
||||
значение свойства прямо с доски.
|
||||
</p>
|
||||
<h3>Настройки под разные базы</h3>
|
||||
<p class="section__prose">
|
||||
У вида четыре группы настроек: General, Title, Properties и Cover. В них задаются ширина
|
||||
карточек, число колонок внутри группы (от 1 до 6), порядок колонок, зебра и masonry.
|
||||
Порядок можно оставить автоматическим или задать вручную; пустые колонки в этом списке
|
||||
сохраняются. Сетка показывает несколько карточек рядом, masonry заполняет вертикальные
|
||||
пустоты, а зебра помогает не сбиться при чтении широкой доски. Отдельно настраиваются заголовки, чипы, даты
|
||||
и обложки. Один вид подстраивается под разные базы, а не наоборот.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../../assets/card-columns-obsidian/filter-use.webp" alt="Панель тегов для фильтрации карточек в Card Columns" width="1280" height="796" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Фильтрация карточек по тегам</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Карточки и обложки</h3>
|
||||
<p class="section__prose">
|
||||
По каждой заметке рисуются свойства как чипы, текст, теги, ссылки, булевы, даты. Можно
|
||||
показать обложку: из первой картинки в заметке или из отдельного свойства. У обложки
|
||||
полный контроль, соотношение сторон (Auto, 1:1, 3:2, 4:3, 16:9), рамка, вписывание
|
||||
(cover/contain), ориентация и место на карточке (над заголовком, под ним, после всего).
|
||||
</p>
|
||||
|
||||
<h3>Решение: настройки вынесены из кода</h3>
|
||||
<p class="section__prose">
|
||||
Сначала параметры были захардкожены под мою базу. Это ошибка: вид перестал бы работать
|
||||
для чужого сценария. Вынес всё в gear-меню, разбив на четыре секции, чтобы вид
|
||||
подстраивался под разные базы, а не под мой единственный случай. Больше 15 параметров.
|
||||
</p>
|
||||
<details class="case-details">
|
||||
<summary>Показать полный список настроек</summary>
|
||||
<p class="section__prose"><strong>General</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Куда открывать карточку: активная панель, всплывающее окно, новая вкладка, сплит вправо / вниз.</li>
|
||||
<li>Ширина карточки (px).</li>
|
||||
<li>Колонок в группе (1–6), сетка внутри колонки.</li>
|
||||
<li>Зебра колонок (чередование фона для сканирования).</li>
|
||||
<li>Masonry-раскладка (карточки заполняют вертикальные пустоты).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Title</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Перенос заголовка, жирный заголовок, размер шрифта (px).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Properties</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Раскладка чипов: стек (вертикально) или сетка (компактно в строку).</li>
|
||||
<li>Перенос многострочных значений, размер шрифта.</li>
|
||||
<li>Формат даты и даты-времени + локаль (Moment.js).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Cover</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Источник: нет / первая картинка в заметке / свойство-обложка.</li>
|
||||
<li>Стиль (без рамки / с рамкой), соотношение сторон, ориентация, вписывание, позиция на карточке.</li>
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<p class="case-todo__q">
|
||||
Это правда про захардкоженные параметры? Если нет, замени на реальную причину выноса
|
||||
в настройки: просьбы пользователей, несколько баз с разной структурой, что угодно.
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: да, первая версия была под мою базу, настройки появились, когда
|
||||
понадобилось открыть плагин наружу. Проверить и поправить.
|
||||
</p>
|
||||
</div>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">💡</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
Сплит-превью сделал как в самом Obsidian: левый клик переиспользует панель, Ctrl+Клик,
|
||||
новую вкладку внутри сплита. Без этого на широком экране карточки неудобно
|
||||
просматривать рядом с доской.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<h3>Работает внутри штатного тулбара</h3>
|
||||
<p class="section__prose">
|
||||
Вид цепляется к BasesView-фреймворку, поэтому сортировка, фильтр, свойства и поиск из
|
||||
тулбара Bases остаются рабочими. Плагин только рисует результат запроса, данные не
|
||||
дублируются и не зависят от отдельного хранилища.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../../assets/card-columns-obsidian/view-configure.webp" alt="Окно настройки вида Columns с параметрами карточек и ширины колонок" width="1280" height="1183" loading="lazy" decoding="async" data-image-viewer />
|
||||
<img src="../../assets/card-columns-obsidian/view-configure.webp" alt="Экран настройки вида Columns" width="1280" height="1183" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Настройки вида Columns</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="rezultat">
|
||||
<h2>Результат и как я это мерял</h2>
|
||||
<h2>Результат: доска внутри Obsidian Bases</h2>
|
||||
<p class="section__prose">
|
||||
Вид закрыл мою боль: Bases-запрос теперь читается как доска, а не как плоская лента
|
||||
карточек. Группировка по свойству + отбор по тегам И/ИЛИ, то, чего не хватало штатному
|
||||
виду. Всё крутится на запросе Bases, так что перенос vault-а и синхронизация ничего не
|
||||
ломают.
|
||||
Card Columns оставляет заметки в Bases, но меняет способ их обзора: я задаю группировку,
|
||||
отбираю теги и открываю карточки рядом с доской. Когда нужна смена статуса, перетаскивание
|
||||
правит то же frontmatter-свойство, по которому строятся колонки. Я продолжаю пользоваться
|
||||
Columns в своей базе: заметки остаются в vault, отдельную доску синхронизировать не нужно.
|
||||
</p>
|
||||
|
||||
<h3>Замер: сколько действий на отбор</h3>
|
||||
<p class="section__prose">
|
||||
Главная задача, по которой я мерял успех: отобрать заметки по двум тегам и найти нужную
|
||||
карточку. В штатном виде карточек это скролл ленты с поиском по заголовкам глазами. В
|
||||
Columns, два клика по пилюлям и колонка перед глазами.
|
||||
</p>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<p class="case-todo__q">
|
||||
Можешь прогнать этот замер по-настоящему? Засечь время на 10 повторах задачи: штатный
|
||||
вид против Columns. Или посчитать точное число действий.
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: на выборке из 25 заметок отбор по двум тегам занимал около 40 секунд и
|
||||
требовал скроллить ленту; в Columns, два клика, примерно 5 секунд. Цифры примерные,
|
||||
заменить на замеренные.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h3>Замер: живучесть в ежедневной работе</h3>
|
||||
<p class="section__prose">
|
||||
Второй критерий субъективнее, но для инструмента под себя он важнее: продолжаю ли я
|
||||
пользоваться плагином через месяц. Пользуюсь, он встроился в работу с базой и не требует
|
||||
вспоминать, как им управлять.
|
||||
</p>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<p class="case-todo__q">
|
||||
Есть ли внешние сигналы: установки, звёзды на GitHub, отзывы, вопросы в issue? Любая
|
||||
цифра, подтверждающая, что плагином пользуются не только ты.
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: плагин пока ставится вручную, через каталог комьюнити не прошёл, так
|
||||
что установок единицы и звёзд пока нет. Если есть реальные данные, вписать их сюда,
|
||||
это сильнее любого-self-report.
|
||||
</p>
|
||||
</div>
|
||||
<p class="section__prose">
|
||||
Что сделал бы иначе. Drag-and-drop карточек между колонками не стал делать сознательно,
|
||||
это меняет свойство в заметке, и для view-плагина это отдельный риск целостности данных.
|
||||
Но вижу запрос на это у пользователей, и, возможно, добавлю как опциональный режим. А
|
||||
пока плагин живёт вручную (через community-каталог ещё не прошёл), это единственное, что
|
||||
мешает им пользоваться сходу.
|
||||
На скриншоте моя база Links: Obsidian показывает 196 результатов. Плагин уже опубликован
|
||||
в каталоге Obsidian Community. На момент обновления кейса там указаны версия 0.9.0 и
|
||||
846 загрузок; поддерживаются Obsidian 1.8.0+, Desktop и Mobile, лицензия MIT.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">✅</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
Главный вывод: вид для Bases получается рабочим только тогда, когда он уважает
|
||||
тулбар фреймворка. Я добавил представление, а не вторую систему хранения, и заметки
|
||||
остались обычными заметками.
|
||||
Для меня важна граница между обзором и изменением данных. Группировка и фильтр помогают
|
||||
читать базу; перенос карточки меняет её свойство. В Columns это действие видно и его
|
||||
можно отключить.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Case Study: Card Columns, a view plugin for Obsidian Bases. It displays notes as cards arranged in columns, with tag filtering using AND/OR."
|
||||
content="How I built Card Columns for Obsidian Bases: group notes by properties, filter tags with AND/OR, and move cards between columns."
|
||||
/>
|
||||
<title>Card Columns, a plugin for Obsidian Bases: a case study</title>
|
||||
<title>Card Columns for Obsidian Bases: Kanban view case study</title>
|
||||
<script>
|
||||
(function () {
|
||||
var FONT_CSS = {
|
||||
@@ -112,20 +112,20 @@
|
||||
<meta property="og:site_name" content="Nikolai Mamadaev — Product Designer" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:locale:alternate" content="ru_RU" />
|
||||
<meta property="og:title" content="Card Columns, a plugin for Obsidian Bases: a case study" />
|
||||
<meta property="og:description" content="Case Study: Card Columns, a view plugin for Obsidian Bases. It displays notes as cards arranged in columns, with tag filtering using AND/OR." />
|
||||
<meta property="og:title" content="Card Columns for Obsidian Bases: Kanban view case study" />
|
||||
<meta property="og:description" content="How I built Card Columns for Obsidian Bases: group notes by properties, filter tags with AND/OR, and move cards between columns." />
|
||||
<meta property="og:url" content="https://mamadaevv.site/en/cases/card-columns-obsidian/" />
|
||||
<meta property="og:image" content="https://mamadaevv.site/assets/og/og-default.png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="Card Columns, a plugin for Obsidian Bases: a case study" />
|
||||
<meta property="og:image:alt" content="Card Columns for Obsidian Bases: Kanban view case study" />
|
||||
|
||||
<!-- Twitter / X -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Card Columns, a plugin for Obsidian Bases: a case study" />
|
||||
<meta name="twitter:description" content="Case Study: Card Columns, a view plugin for Obsidian Bases. It displays notes as cards arranged in columns, with tag filtering using AND/OR." />
|
||||
<meta name="twitter:title" content="Card Columns for Obsidian Bases: Kanban view case study" />
|
||||
<meta name="twitter:description" content="How I built Card Columns for Obsidian Bases: group notes by properties, filter tags with AND/OR, and move cards between columns." />
|
||||
<meta name="twitter:image" content="https://mamadaevv.site/assets/og/og-default.png" />
|
||||
<meta name="twitter:image:alt" content="Card Columns, a plugin for Obsidian Bases: a case study" />
|
||||
<meta name="twitter:image:alt" content="Card Columns for Obsidian Bases: Kanban view case study" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
@@ -169,8 +169,8 @@
|
||||
"@type": "CreativeWork",
|
||||
"@id": "https://mamadaevv.site/en/cases/card-columns-obsidian/#page",
|
||||
"url": "https://mamadaevv.site/en/cases/card-columns-obsidian/",
|
||||
"name": "Card Columns, a plugin for Obsidian Bases: a case study",
|
||||
"description": "Case Study: Card Columns, a view plugin for Obsidian Bases. It displays notes as cards arranged in columns, with tag filtering using AND/OR.",
|
||||
"name": "Card Columns for Obsidian Bases: Kanban view case study",
|
||||
"description": "How I built Card Columns for Obsidian Bases: group notes by properties, filter tags with AND/OR, and move cards between columns.",
|
||||
"isPartOf": {
|
||||
"@id": "https://mamadaevv.site/#website"
|
||||
},
|
||||
@@ -203,7 +203,7 @@
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 3,
|
||||
"name": "Card Columns, a plugin for Obsidian Bases: a case study",
|
||||
"name": "Card Columns for Obsidian Bases: Kanban view case study",
|
||||
"item": "https://mamadaevv.site/cases/card-columns-obsidian/"
|
||||
}
|
||||
]
|
||||
@@ -256,72 +256,7 @@
|
||||
.case-article a:not(.btn) {
|
||||
color: var(--accent);
|
||||
}
|
||||
.case-article .case-brief {
|
||||
list-style: none;
|
||||
margin: 1.5rem 0 0;
|
||||
padding: 1.1rem 1.25rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
|
||||
gap: 0.85rem 1.5rem;
|
||||
font-size: 0.9rem;
|
||||
border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
|
||||
border-radius: var(--radius-md, 12px);
|
||||
}
|
||||
.case-article .case-brief li {
|
||||
margin: 0;
|
||||
}
|
||||
.case-article .case-brief span {
|
||||
display: block;
|
||||
margin-bottom: 0.15rem;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.case-article .case-todo {
|
||||
margin: 1rem 0 1.25rem;
|
||||
padding: 0.9rem 1.1rem;
|
||||
border-left: 2px solid var(--accent);
|
||||
background: color-mix(in srgb, var(--accent) 8%, transparent);
|
||||
border-radius: 0 var(--radius-sm, 8px) var(--radius-sm, 8px) 0;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
.case-article .case-todo p {
|
||||
margin: 0 0 0.5rem;
|
||||
}
|
||||
.case-article .case-todo p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.case-article .case-todo__q {
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
}
|
||||
.case-todo__label {
|
||||
display: block;
|
||||
margin-bottom: 0.35rem;
|
||||
font-size: 0.68rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--accent);
|
||||
opacity: 0.85;
|
||||
}
|
||||
.case-article details.case-details {
|
||||
margin: 0.75rem 0 1rem;
|
||||
padding: 0.6rem 0.9rem;
|
||||
border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
|
||||
border-radius: var(--radius-sm, 8px);
|
||||
}
|
||||
.case-article details.case-details > summary {
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
.case-article details.case-details[open] > summary {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.case-block {
|
||||
margin-top: 3rem;
|
||||
padding-top: 2.5rem;
|
||||
@@ -492,315 +427,136 @@
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">Obsidian Bases · Plugin</p>
|
||||
<h1 class="case-page__h1">
|
||||
A Kanban view for Obsidian Bases<br />
|
||||
that leaves your notes untouched
|
||||
A Kanban board for Obsidian Bases<br />
|
||||
with filtering and drag-and-drop
|
||||
</h1>
|
||||
<p class="case-page__sub">
|
||||
Card Columns: Notes as cards in columns,<br />
|
||||
filtered by AND/OR tags with just two clicks
|
||||
Card Columns: group by properties,<br />
|
||||
filter tags with AND/OR
|
||||
</p>
|
||||
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../../../assets/card-columns-obsidian/overview.webp" alt="An Obsidian links database grouped into Card Columns by tags" width="2084" height="1296" loading="eager" decoding="async" data-image-viewer />
|
||||
<figcaption>A notes database grouped into Columns by tags</figcaption>
|
||||
<figcaption>Links: 196 results in Columns view</figcaption>
|
||||
</figure>
|
||||
|
||||
<ul class="case-brief">
|
||||
<li>Role: Product Design and Development</li>
|
||||
<li><span>Platform:</span> Obsidian Bases</li>
|
||||
<li><span>Status</span>: Working plugin in the <a href="https://community.obsidian.md/plugins/card-columns" target="_blank" rel="noopener noreferrer">Obsidian plugin directory</a>, open source (MIT)</li>
|
||||
<li><span>Team: Solo</span>, side project</li>
|
||||
<li><span>Status:</span> Draft response, to be replaced</li>
|
||||
</ul>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
How long did it take from the initial idea to a working version? Weeks? A month of weekends?
|
||||
</p>
|
||||
<p>
|
||||
Draft answer: I put it together in three weeks in the evenings, then spent another month refining it while
|
||||
working on my own projects. Replace with the actual time.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="section__prose">
|
||||
Obsidian now has Bases, a separate file type that displays notes not as text, but
|
||||
in various formats: tables, cards, and trees. The standard card view didn’t work for me: it’s
|
||||
flat, with no grouping, and it’s hard to make sense of when there are hundreds of notes. I wanted to see them
|
||||
arranged in columns, like a Kanban board, but without the extra overhead. That’s how the Card Columns view plugin came about.
|
||||
Card Columns is my view plugin for Obsidian Bases. I designed and built it myself because I wanted
|
||||
to scan notes in columns instead of searching through the standard Cards feed. The plugin is
|
||||
available in the <a href="https://community.obsidian.md/plugins/card-columns" target="_blank" rel="noopener noreferrer">Obsidian Community directory</a>
|
||||
and is open source under the MIT license.
|
||||
</p>
|
||||
|
||||
<div class="case-block" id="kontekst">
|
||||
<h2>Context</h2>
|
||||
<h2>From a Bases query to columns</h2>
|
||||
<p class="section__prose">
|
||||
A “Bases” is neither a note nor a separate database. It’s a query to the vault: you select
|
||||
notes using a filter, and the framework displays them in the chosen view. Obsidian itself has
|
||||
a built-in card view, but it’s one-dimensional: no grouping by properties, no
|
||||
proper filtering. I decided to create my own view that integrates into the
|
||||
Bases toggle alongside the default ones.
|
||||
A <code>.base</code> file describes a query over notes in the vault: which entries to show and
|
||||
which properties to display. In my database, Obsidian’s built-in Cards view produced a long
|
||||
feed. I wanted to see the same results grouped by a property such as status or tag.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
The main limitation was in the framework itself: the plugin doesn’t store data, but rather renders what
|
||||
the Bases query returns (Sort, Filter, Properties, Search from the toolbar). This means that all the logic
|
||||
for data retrieval remains with Bases, and my task is solely to display and navigate the results.
|
||||
Columns registers as another BasesView and receives the query results. Sorting, filters, visible
|
||||
properties, and search stay in the native toolbar. I chose not to create a separate board: the
|
||||
notes and query settings remain in Bases; the plugin changes only how they are displayed.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="pochemu-svoi">
|
||||
<h2>Why not use a ready-made solution?</h2>
|
||||
<div class="case-block" id="filters">
|
||||
<h2>Group first, filter second</h2>
|
||||
<p class="section__prose">
|
||||
Before writing any code, I checked what was already available. Three options, none of them worked:
|
||||
I set grouping through Group by in the Bases toolbar: tags, status, category, or any frontmatter
|
||||
property. If none is selected, Columns groups by tags. The columns use that property’s values;
|
||||
the underlying query stays the same. To view the database from another angle, I only change
|
||||
its grouping.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<strong>The default Bases card view.</strong>
|
||||
It displays a continuous stream of cards without grouping.
|
||||
When there are over a hundred notes, it becomes a feed where you have to scroll and squint at the titles.
|
||||
I ruled that out first.
|
||||
I put tag filters right below the toolbar. Click one tag to keep only notes with it. Click another
|
||||
to add it in OR mode. Ctrl-click or right-click toggles one tag without clearing the rest, and
|
||||
the OR/AND control changes how multiple selections combine:
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<strong>Kanban plugins from the community.</strong>
|
||||
Most come with their own storage system:
|
||||
the board exists separately from the vault, and notes are duplicated. This results in a second database
|
||||
that needs to be synchronized. I didn’t need that.
|
||||
These pills do not replace Filter in the toolbar. Bases creates the initial result set; the tag
|
||||
filter narrows it inside Columns. I can inspect a subset without changing the underlying query.
|
||||
</p>
|
||||
<ul class="section__prose">
|
||||
<li>the first tag narrows the view to notes that have it;</li>
|
||||
<li>the next adds notes with any of the selected tags;</li>
|
||||
<li>Ctrl-click or right-click toggles a single tag in the current selection;</li>
|
||||
<li>OR/AND switches between “any selected” and “all selected”; All clears the selection.</li>
|
||||
</ul>
|
||||
<p class="section__prose">
|
||||
<strong>The neighboring bases-kanban.</strong>
|
||||
The closest in spirit: it hooks into Bases to create
|
||||
a Kanban board. But it writes to the notes: dragging a card changes the frontmatter. For a view plugin,
|
||||
this is a risk, which I’ll discuss below.
|
||||
The filter stays visible beside the board. A modal would interrupt the flow: I would have to close
|
||||
it just to check what changed.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">📌</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
The decision to forgo drag-and-drop isn’t a shortcoming—it’s a design choice. A view plugin should not
|
||||
write to user data. This decision shaped everything else.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Did you actually install and test other people’s plugins, or did you just go by the descriptions? Which
|
||||
ones did you look at specifically?
|
||||
</p>
|
||||
<p>
|
||||
Preliminary answer: I installed three of them, ran them for a week on my database, then uninstalled them. I looked at the source code for bases-kanban
|
||||
but didn’t install it. Replace with actual information; include the plugin names.
|
||||
</p>
|
||||
</div>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../../../assets/card-columns-obsidian/filter-use.webp" alt="Tag filters above Card Columns cards and columns" width="1280" height="796" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Tag filters stay beside the columns</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="zadacha">
|
||||
<h2>Task</h2>
|
||||
<div class="case-block" id="cards">
|
||||
<h2>Cards show the fields I need</h2>
|
||||
<p class="section__prose">
|
||||
Design a view for Bases that displays notes as cards arranged in columns and allows you to
|
||||
quickly select the ones you need. Strict constraint: the plugin does not write anything to the notes and does not store
|
||||
its own state, and sorting, filtering, properties, and search from the standard Bases toolbar must
|
||||
work as before.
|
||||
The card contents follow the native Properties selection. The first selected property becomes
|
||||
the title; the rest appear as chips: text, tags, links, booleans, and dates. Chips can use a vertical
|
||||
stack or compact grid, with configurable wrapping and date formats.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
When a database needs covers, Columns can use the first image in a note or a chosen frontmatter
|
||||
property. I can set the aspect ratio (Auto, 1:1, 3:2, 4:3, or 16:9), fit, and position. Cards can
|
||||
open in the active pane, a floating modal, a new tab, or a split pane. In a split, a click reuses
|
||||
the pane; Ctrl-click opens a new tab. That keeps the note beside the board without losing the
|
||||
current query context.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">📌</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
The main risk is creating a view that conflicts with the standard Bases toolbar. If that happens,
|
||||
the user loses the sorting and search capabilities—the very features that make Bases worth using. This could not
|
||||
be allowed to happen.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="reshenie">
|
||||
<h2>Solutions</h2>
|
||||
<h2>Dragging a card edits its note</h2>
|
||||
<p class="section__prose">
|
||||
The plugin adds a “Columns” view to Bases. Cards are built from the results of a Bases query;
|
||||
grouping is defined by a property, and filtering is done via clickable tags. Next, there are five options
|
||||
that determine the result. Each one includes something I decided against.
|
||||
</p>
|
||||
<!-- МЕДИА: скриншот вида с колонками и карточками внутри.
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../assets/card-columns-obsidian/board.webp" alt="Columns of cards grouped by property" width="1920" height="1080" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>View with columns</figcaption>
|
||||
</figure>
|
||||
-->
|
||||
|
||||
<h3>Grouping by any property</h3>
|
||||
<p class="section__prose">
|
||||
Columns are generated using the “Group by” option in the Bases toolbar, by tag, status, category, or any
|
||||
frontmatter property. Change the property in the query, and the board reloads automatically. This way, a single
|
||||
database covers different perspectives: projects by status, notes by tags, tasks by
|
||||
priority.
|
||||
</p>
|
||||
|
||||
<h3>Tag filter by AND and OR</h3>
|
||||
<p class="section__prose">
|
||||
This is exactly what the plugin was designed for. Below the toolbar, there are tag icons; when clicked, they
|
||||
filter cards across all columns at once:
|
||||
</p>
|
||||
<ul class="section__prose">
|
||||
<li>Left-click on a tag to show only that tag (resets the other filters).</li>
|
||||
<li>Left-click on the next tag to show notes with ANY of the selected tags (OR mode).</li>
|
||||
<li>Ctrl+Click or right-click to switch tags without resetting the selection.</li>
|
||||
<li>The OR/AND button: toggle between “any of” and “all of” for multiple tags.</li>
|
||||
<li>All: Clear all filters.</li>
|
||||
</ul>
|
||||
<p class="section__prose">
|
||||
The combination of “OR—add with a left-click + exact toggle via Ctrl” turned out to be intuitive:
|
||||
quick selection doesn’t disrupt what’s already selected. I immediately rejected the alternative—moving the filter to a modal window—
|
||||
because it requires an extra click and loses the context of what’s already been filtered.
|
||||
In version 0.9.0, a card can be dragged into another column. That movement changes data: Columns
|
||||
updates the frontmatter property used for grouping through Obsidian’s
|
||||
<code>processFrontMatter()</code> API. If the board is grouped by status, dropping a card into a
|
||||
different column changes that note’s status. For a multi-value property, the old value is removed,
|
||||
the new one is added, and the other values stay in place.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
The choice here isn’t about the feature itself, but where it lives. I chose the pills below the toolbar instead of
|
||||
a separate filter window because filtering by tags is an action performed at every step of working
|
||||
with the database. A modal window turns it into an interrupted workflow: open, configure, close, check.
|
||||
The pill-shaped icons keep the result right in front of you, and the filter status is always visible.
|
||||
Drag-and-drop is enabled by default, but it can be turned off in General settings. The choice is
|
||||
explicit: use the board to inspect groups, or edit the grouping property by moving a card.
|
||||
</p>
|
||||
<h3>Settings for different databases</h3>
|
||||
<p class="section__prose">
|
||||
The view has four settings groups: General, Title, Properties, and Cover. They cover card width,
|
||||
one to six cards per group, column order, zebra striping, and masonry. Column order can be automatic
|
||||
or set manually, with empty columns kept in place. The grid places cards side by side,
|
||||
masonry fills vertical gaps, and zebra striping helps scan a wide board. Title style,
|
||||
property chips, dates, and covers have their own controls. The view adapts to the database.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../../../assets/card-columns-obsidian/filter-use.webp" alt="Tag pills used to filter cards in Card Columns" width="1280" height="796" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Filtering cards by tag</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Cards and Covers</h3>
|
||||
<p class="section__prose">
|
||||
Properties such as chips, text, tags, links, Booleans, and dates are displayed for each note. You can
|
||||
show a cover: from the first image in the note or from a separate property. You have
|
||||
full control over the cover, including aspect ratio (Auto, 1:1, 3:2, 4:3, 16:9), border, fit
|
||||
(cover/contain), orientation, and position on the card (above the title, below it, at the end).
|
||||
</p>
|
||||
|
||||
<h3>Solution: Settings have been moved out of the code</h3>
|
||||
<p class="section__prose">
|
||||
At first, the parameters were hardcoded for my database. This was a mistake: the view would stop working
|
||||
for someone else’s scenario. I moved everything to the gear menu, dividing it into four sections so that the view
|
||||
could adapt to different databases, rather than just my single use case. More than 15 parameters.
|
||||
</p>
|
||||
<details class="case-details">
|
||||
<summary>Show the full list of settings</summary>
|
||||
<p class="section__prose"><strong>General</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Where to open the card: active panel, pop-up window, new tab, split to the right / down.</li>
|
||||
<li>Card width (px).</li>
|
||||
<li>Columns per group (1–6), grid within a column.</li>
|
||||
<li>Zebra columns (alternating background colors for easy scanning).</li>
|
||||
<li>Masonry layout (cards fill vertical gaps).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Title</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Title wrapping, bold title, font size (px).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Properties</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Chip layout: stack (vertical) or grid (compact in a row).</li>
|
||||
<li>Wrap multi-line values, font size.</li>
|
||||
<li>Date and date-time formats + locale (Moment.js).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Cover</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Source: none / first image in the post / cover property.</li>
|
||||
<li>Style (borderless / with border), aspect ratio, orientation, fit, position on the card.</li>
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Is it true about the hard-coded parameters? If not, replace it with the real reason for moving them
|
||||
to the settings: user requests, multiple databases with different structures, whatever.
|
||||
</p>
|
||||
<p>
|
||||
Preliminary answer: Yes, the first version was tailored to my database; the settings were added when
|
||||
I needed to make the plugin available externally. I’ll check and fix it.
|
||||
</p>
|
||||
</div>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">💡</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
I implemented the split preview just like in Obsidian itself: left-click reuses the panel, Ctrl+click opens
|
||||
a new tab within the split. Without this, on a wide screen, it’s inconvenient to
|
||||
view cards next to the board.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<h3>Works within the standard toolbar</h3>
|
||||
<p class="section__prose">
|
||||
The view hooks into the BasesView framework, so sorting, filtering, properties, and search from
|
||||
the Bases toolbar remain functional. The plugin only renders the query results; the data is not
|
||||
duplicated and does not depend on a separate storage.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../../../assets/card-columns-obsidian/view-configure.webp" alt="Configure view popover with card and column width settings" width="1280" height="1183" loading="lazy" decoding="async" data-image-viewer />
|
||||
<img src="../../../assets/card-columns-obsidian/view-configure.webp" alt="Columns view configuration screen" width="1280" height="1183" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Columns view settings</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="rezultat">
|
||||
<h2>The Result and How I Tested It</h2>
|
||||
<h2>Result: a board inside Obsidian Bases</h2>
|
||||
<p class="section__prose">
|
||||
This view solved my problem: a Bases query now reads like a board, rather than a flat stream
|
||||
of cards. Grouping by property + filtering by AND/OR tags—exactly what the default
|
||||
view was missing. Everything runs on the Bases query, so moving the vault and syncing don’t
|
||||
break anything.
|
||||
Card Columns keeps notes in Bases but changes how I scan them: I choose a grouping, filter tags,
|
||||
and open cards beside the board. When I need to change a status, dragging a card updates the same
|
||||
frontmatter property that forms the columns. I still use Columns with my own database; notes stay
|
||||
in the vault, so there is no separate board to keep in sync.
|
||||
</p>
|
||||
|
||||
<h3>Metrics: number of steps to filter</h3>
|
||||
<p class="section__prose">
|
||||
The main task I used to measure success: filter notes by two tags and find the right
|
||||
card. In the standard card view, this involves scrolling through the feed and scanning the titles with your eyes. In
|
||||
Columns, two clicks on the pills and the column is right in front of you.
|
||||
</p>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Can you run this test for real? Time 10 repetitions of the task: the default
|
||||
view versus Columns. Or count the exact number of steps.
|
||||
</p>
|
||||
<p>
|
||||
Preliminary answer: on a sample of 25 notes, filtering by two tags took about 40 seconds and
|
||||
required scrolling through the feed; in Columns, two clicks, about 5 seconds. These are rough estimates—
|
||||
replace them with actual measurements.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h3>Test: Long-term usability in daily work</h3>
|
||||
<p class="section__prose">
|
||||
The second criterion is more subjective, but for a tool tailored to my needs, it’s more important: will I still be
|
||||
using the plugin a month from now? I am—it’s become an integral part of my work with the database and doesn’t require
|
||||
me to remember how to use it.
|
||||
</p>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Are there any external indicators: installs, GitHub stars, reviews, or questions in the issue tracker? Any
|
||||
number confirming that you’re not the only one using the plugin.
|
||||
</p>
|
||||
<p>
|
||||
Preliminary answer: The plugin currently needs to be installed manually; it hasn’t been approved for the community repository yet, so
|
||||
there are only a handful of installs and no stars so far. If there’s actual data, include it here—
|
||||
it’s more convincing than any self-report.
|
||||
</p>
|
||||
</div>
|
||||
<p class="section__prose">
|
||||
What I’d do differently. I deliberately chose not to implement drag-and-drop of cards between columns,
|
||||
since that changes a property in the note, and for a view plugin, that poses a separate data integrity risk.
|
||||
But I see a demand for this among users, and I might add it as an optional mode. For
|
||||
now, since the plugin is maintained manually (it hasn’t been reviewed by the community directory yet), this is the only thing
|
||||
preventing users from using it right away.
|
||||
The screenshot shows my Links database; Obsidian displays 196 results. The plugin is listed in
|
||||
Obsidian Community. When I updated this case, the listing showed version 0.9.0 and 846 downloads;
|
||||
it supports Obsidian 1.8.0+, desktop and mobile, under the MIT license.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">✅</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
Main conclusion: a view for Bases only works when it respects
|
||||
the framework’s toolbar. I added a view, not a second storage system, and the notes
|
||||
remained regular notes.
|
||||
I care about the boundary between viewing and changing data. Grouping and filtering help me
|
||||
read the database; moving a card edits its property. In Columns, that action is visible and
|
||||
can be turned off.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Case Study: Card Columns, a view plugin for Obsidian Bases. It displays notes as cards arranged in columns, with tag filtering using AND/OR."
|
||||
content="How I built Card Columns for Obsidian Bases: group notes by properties, filter tags with AND/OR, and move cards between columns."
|
||||
/>
|
||||
<title>Card Columns, a plugin for Obsidian Bases: a case study</title>
|
||||
<title>Card Columns for Obsidian Bases: Kanban view case study</title>
|
||||
{{> head-links}}
|
||||
{{> head-plyr}}
|
||||
<style>
|
||||
@@ -48,72 +48,7 @@
|
||||
.case-article a:not(.btn) {
|
||||
color: var(--accent);
|
||||
}
|
||||
.case-article .case-brief {
|
||||
list-style: none;
|
||||
margin: 1.5rem 0 0;
|
||||
padding: 1.1rem 1.25rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
|
||||
gap: 0.85rem 1.5rem;
|
||||
font-size: 0.9rem;
|
||||
border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
|
||||
border-radius: var(--radius-md, 12px);
|
||||
}
|
||||
.case-article .case-brief li {
|
||||
margin: 0;
|
||||
}
|
||||
.case-article .case-brief span {
|
||||
display: block;
|
||||
margin-bottom: 0.15rem;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.case-article .case-todo {
|
||||
margin: 1rem 0 1.25rem;
|
||||
padding: 0.9rem 1.1rem;
|
||||
border-left: 2px solid var(--accent);
|
||||
background: color-mix(in srgb, var(--accent) 8%, transparent);
|
||||
border-radius: 0 var(--radius-sm, 8px) var(--radius-sm, 8px) 0;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
.case-article .case-todo p {
|
||||
margin: 0 0 0.5rem;
|
||||
}
|
||||
.case-article .case-todo p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.case-article .case-todo__q {
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
}
|
||||
.case-todo__label {
|
||||
display: block;
|
||||
margin-bottom: 0.35rem;
|
||||
font-size: 0.68rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--accent);
|
||||
opacity: 0.85;
|
||||
}
|
||||
.case-article details.case-details {
|
||||
margin: 0.75rem 0 1rem;
|
||||
padding: 0.6rem 0.9rem;
|
||||
border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
|
||||
border-radius: var(--radius-sm, 8px);
|
||||
}
|
||||
.case-article details.case-details > summary {
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
.case-article details.case-details[open] > summary {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.case-block {
|
||||
margin-top: 3rem;
|
||||
padding-top: 2.5rem;
|
||||
@@ -179,315 +114,136 @@
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">Obsidian Bases · Plugin</p>
|
||||
<h1 class="case-page__h1">
|
||||
A Kanban view for Obsidian Bases<br />
|
||||
that leaves your notes untouched
|
||||
A Kanban board for Obsidian Bases<br />
|
||||
with filtering and drag-and-drop
|
||||
</h1>
|
||||
<p class="case-page__sub">
|
||||
Card Columns: Notes as cards in columns,<br />
|
||||
filtered by AND/OR tags with just two clicks
|
||||
Card Columns: group by properties,<br />
|
||||
filter tags with AND/OR
|
||||
</p>
|
||||
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/card-columns-obsidian/overview.webp" alt="An Obsidian links database grouped into Card Columns by tags" width="2084" height="1296" loading="eager" decoding="async" data-image-viewer />
|
||||
<figcaption>A notes database grouped into Columns by tags</figcaption>
|
||||
<figcaption>Links: 196 results in Columns view</figcaption>
|
||||
</figure>
|
||||
|
||||
<ul class="case-brief">
|
||||
<li>Role: Product Design and Development</li>
|
||||
<li><span>Platform:</span> Obsidian Bases</li>
|
||||
<li><span>Status</span>: Working plugin in the <a href="https://community.obsidian.md/plugins/card-columns" target="_blank" rel="noopener noreferrer">Obsidian plugin directory</a>, open source (MIT)</li>
|
||||
<li><span>Team: Solo</span>, side project</li>
|
||||
<li><span>Status:</span> Draft response, to be replaced</li>
|
||||
</ul>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
How long did it take from the initial idea to a working version? Weeks? A month of weekends?
|
||||
</p>
|
||||
<p>
|
||||
Draft answer: I put it together in three weeks in the evenings, then spent another month refining it while
|
||||
working on my own projects. Replace with the actual time.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="section__prose">
|
||||
Obsidian now has Bases, a separate file type that displays notes not as text, but
|
||||
in various formats: tables, cards, and trees. The standard card view didn’t work for me: it’s
|
||||
flat, with no grouping, and it’s hard to make sense of when there are hundreds of notes. I wanted to see them
|
||||
arranged in columns, like a Kanban board, but without the extra overhead. That’s how the Card Columns view plugin came about.
|
||||
Card Columns is my view plugin for Obsidian Bases. I designed and built it myself because I wanted
|
||||
to scan notes in columns instead of searching through the standard Cards feed. The plugin is
|
||||
available in the <a href="https://community.obsidian.md/plugins/card-columns" target="_blank" rel="noopener noreferrer">Obsidian Community directory</a>
|
||||
and is open source under the MIT license.
|
||||
</p>
|
||||
|
||||
<div class="case-block" id="kontekst">
|
||||
<h2>Context</h2>
|
||||
<h2>From a Bases query to columns</h2>
|
||||
<p class="section__prose">
|
||||
A “Bases” is neither a note nor a separate database. It’s a query to the vault: you select
|
||||
notes using a filter, and the framework displays them in the chosen view. Obsidian itself has
|
||||
a built-in card view, but it’s one-dimensional: no grouping by properties, no
|
||||
proper filtering. I decided to create my own view that integrates into the
|
||||
Bases toggle alongside the default ones.
|
||||
A <code>.base</code> file describes a query over notes in the vault: which entries to show and
|
||||
which properties to display. In my database, Obsidian’s built-in Cards view produced a long
|
||||
feed. I wanted to see the same results grouped by a property such as status or tag.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
The main limitation was in the framework itself: the plugin doesn’t store data, but rather renders what
|
||||
the Bases query returns (Sort, Filter, Properties, Search from the toolbar). This means that all the logic
|
||||
for data retrieval remains with Bases, and my task is solely to display and navigate the results.
|
||||
Columns registers as another BasesView and receives the query results. Sorting, filters, visible
|
||||
properties, and search stay in the native toolbar. I chose not to create a separate board: the
|
||||
notes and query settings remain in Bases; the plugin changes only how they are displayed.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="pochemu-svoi">
|
||||
<h2>Why not use a ready-made solution?</h2>
|
||||
<div class="case-block" id="filters">
|
||||
<h2>Group first, filter second</h2>
|
||||
<p class="section__prose">
|
||||
Before writing any code, I checked what was already available. Three options, none of them worked:
|
||||
I set grouping through Group by in the Bases toolbar: tags, status, category, or any frontmatter
|
||||
property. If none is selected, Columns groups by tags. The columns use that property’s values;
|
||||
the underlying query stays the same. To view the database from another angle, I only change
|
||||
its grouping.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<strong>The default Bases card view.</strong>
|
||||
It displays a continuous stream of cards without grouping.
|
||||
When there are over a hundred notes, it becomes a feed where you have to scroll and squint at the titles.
|
||||
I ruled that out first.
|
||||
I put tag filters right below the toolbar. Click one tag to keep only notes with it. Click another
|
||||
to add it in OR mode. Ctrl-click or right-click toggles one tag without clearing the rest, and
|
||||
the OR/AND control changes how multiple selections combine:
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<strong>Kanban plugins from the community.</strong>
|
||||
Most come with their own storage system:
|
||||
the board exists separately from the vault, and notes are duplicated. This results in a second database
|
||||
that needs to be synchronized. I didn’t need that.
|
||||
These pills do not replace Filter in the toolbar. Bases creates the initial result set; the tag
|
||||
filter narrows it inside Columns. I can inspect a subset without changing the underlying query.
|
||||
</p>
|
||||
<ul class="section__prose">
|
||||
<li>the first tag narrows the view to notes that have it;</li>
|
||||
<li>the next adds notes with any of the selected tags;</li>
|
||||
<li>Ctrl-click or right-click toggles a single tag in the current selection;</li>
|
||||
<li>OR/AND switches between “any selected” and “all selected”; All clears the selection.</li>
|
||||
</ul>
|
||||
<p class="section__prose">
|
||||
<strong>The neighboring bases-kanban.</strong>
|
||||
The closest in spirit: it hooks into Bases to create
|
||||
a Kanban board. But it writes to the notes: dragging a card changes the frontmatter. For a view plugin,
|
||||
this is a risk, which I’ll discuss below.
|
||||
The filter stays visible beside the board. A modal would interrupt the flow: I would have to close
|
||||
it just to check what changed.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">📌</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
The decision to forgo drag-and-drop isn’t a shortcoming—it’s a design choice. A view plugin should not
|
||||
write to user data. This decision shaped everything else.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Did you actually install and test other people’s plugins, or did you just go by the descriptions? Which
|
||||
ones did you look at specifically?
|
||||
</p>
|
||||
<p>
|
||||
Preliminary answer: I installed three of them, ran them for a week on my database, then uninstalled them. I looked at the source code for bases-kanban
|
||||
but didn’t install it. Replace with actual information; include the plugin names.
|
||||
</p>
|
||||
</div>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/card-columns-obsidian/filter-use.webp" alt="Tag filters above Card Columns cards and columns" width="1280" height="796" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Tag filters stay beside the columns</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="zadacha">
|
||||
<h2>Task</h2>
|
||||
<div class="case-block" id="cards">
|
||||
<h2>Cards show the fields I need</h2>
|
||||
<p class="section__prose">
|
||||
Design a view for Bases that displays notes as cards arranged in columns and allows you to
|
||||
quickly select the ones you need. Strict constraint: the plugin does not write anything to the notes and does not store
|
||||
its own state, and sorting, filtering, properties, and search from the standard Bases toolbar must
|
||||
work as before.
|
||||
The card contents follow the native Properties selection. The first selected property becomes
|
||||
the title; the rest appear as chips: text, tags, links, booleans, and dates. Chips can use a vertical
|
||||
stack or compact grid, with configurable wrapping and date formats.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
When a database needs covers, Columns can use the first image in a note or a chosen frontmatter
|
||||
property. I can set the aspect ratio (Auto, 1:1, 3:2, 4:3, or 16:9), fit, and position. Cards can
|
||||
open in the active pane, a floating modal, a new tab, or a split pane. In a split, a click reuses
|
||||
the pane; Ctrl-click opens a new tab. That keeps the note beside the board without losing the
|
||||
current query context.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">📌</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
The main risk is creating a view that conflicts with the standard Bases toolbar. If that happens,
|
||||
the user loses the sorting and search capabilities—the very features that make Bases worth using. This could not
|
||||
be allowed to happen.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="reshenie">
|
||||
<h2>Solutions</h2>
|
||||
<h2>Dragging a card edits its note</h2>
|
||||
<p class="section__prose">
|
||||
The plugin adds a “Columns” view to Bases. Cards are built from the results of a Bases query;
|
||||
grouping is defined by a property, and filtering is done via clickable tags. Next, there are five options
|
||||
that determine the result. Each one includes something I decided against.
|
||||
</p>
|
||||
<!-- МЕДИА: скриншот вида с колонками и карточками внутри.
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../assets/card-columns-obsidian/board.webp" alt="Columns of cards grouped by property" width="1920" height="1080" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>View with columns</figcaption>
|
||||
</figure>
|
||||
-->
|
||||
|
||||
<h3>Grouping by any property</h3>
|
||||
<p class="section__prose">
|
||||
Columns are generated using the “Group by” option in the Bases toolbar, by tag, status, category, or any
|
||||
frontmatter property. Change the property in the query, and the board reloads automatically. This way, a single
|
||||
database covers different perspectives: projects by status, notes by tags, tasks by
|
||||
priority.
|
||||
</p>
|
||||
|
||||
<h3>Tag filter by AND and OR</h3>
|
||||
<p class="section__prose">
|
||||
This is exactly what the plugin was designed for. Below the toolbar, there are tag icons; when clicked, they
|
||||
filter cards across all columns at once:
|
||||
</p>
|
||||
<ul class="section__prose">
|
||||
<li>Left-click on a tag to show only that tag (resets the other filters).</li>
|
||||
<li>Left-click on the next tag to show notes with ANY of the selected tags (OR mode).</li>
|
||||
<li>Ctrl+Click or right-click to switch tags without resetting the selection.</li>
|
||||
<li>The OR/AND button: toggle between “any of” and “all of” for multiple tags.</li>
|
||||
<li>All: Clear all filters.</li>
|
||||
</ul>
|
||||
<p class="section__prose">
|
||||
The combination of “OR—add with a left-click + exact toggle via Ctrl” turned out to be intuitive:
|
||||
quick selection doesn’t disrupt what’s already selected. I immediately rejected the alternative—moving the filter to a modal window—
|
||||
because it requires an extra click and loses the context of what’s already been filtered.
|
||||
In version 0.9.0, a card can be dragged into another column. That movement changes data: Columns
|
||||
updates the frontmatter property used for grouping through Obsidian’s
|
||||
<code>processFrontMatter()</code> API. If the board is grouped by status, dropping a card into a
|
||||
different column changes that note’s status. For a multi-value property, the old value is removed,
|
||||
the new one is added, and the other values stay in place.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
The choice here isn’t about the feature itself, but where it lives. I chose the pills below the toolbar instead of
|
||||
a separate filter window because filtering by tags is an action performed at every step of working
|
||||
with the database. A modal window turns it into an interrupted workflow: open, configure, close, check.
|
||||
The pill-shaped icons keep the result right in front of you, and the filter status is always visible.
|
||||
Drag-and-drop is enabled by default, but it can be turned off in General settings. The choice is
|
||||
explicit: use the board to inspect groups, or edit the grouping property by moving a card.
|
||||
</p>
|
||||
<h3>Settings for different databases</h3>
|
||||
<p class="section__prose">
|
||||
The view has four settings groups: General, Title, Properties, and Cover. They cover card width,
|
||||
one to six cards per group, column order, zebra striping, and masonry. Column order can be automatic
|
||||
or set manually, with empty columns kept in place. The grid places cards side by side,
|
||||
masonry fills vertical gaps, and zebra striping helps scan a wide board. Title style,
|
||||
property chips, dates, and covers have their own controls. The view adapts to the database.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/card-columns-obsidian/filter-use.webp" alt="Tag pills used to filter cards in Card Columns" width="1280" height="796" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Filtering cards by tag</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Cards and Covers</h3>
|
||||
<p class="section__prose">
|
||||
Properties such as chips, text, tags, links, Booleans, and dates are displayed for each note. You can
|
||||
show a cover: from the first image in the note or from a separate property. You have
|
||||
full control over the cover, including aspect ratio (Auto, 1:1, 3:2, 4:3, 16:9), border, fit
|
||||
(cover/contain), orientation, and position on the card (above the title, below it, at the end).
|
||||
</p>
|
||||
|
||||
<h3>Solution: Settings have been moved out of the code</h3>
|
||||
<p class="section__prose">
|
||||
At first, the parameters were hardcoded for my database. This was a mistake: the view would stop working
|
||||
for someone else’s scenario. I moved everything to the gear menu, dividing it into four sections so that the view
|
||||
could adapt to different databases, rather than just my single use case. More than 15 parameters.
|
||||
</p>
|
||||
<details class="case-details">
|
||||
<summary>Show the full list of settings</summary>
|
||||
<p class="section__prose"><strong>General</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Where to open the card: active panel, pop-up window, new tab, split to the right / down.</li>
|
||||
<li>Card width (px).</li>
|
||||
<li>Columns per group (1–6), grid within a column.</li>
|
||||
<li>Zebra columns (alternating background colors for easy scanning).</li>
|
||||
<li>Masonry layout (cards fill vertical gaps).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Title</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Title wrapping, bold title, font size (px).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Properties</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Chip layout: stack (vertical) or grid (compact in a row).</li>
|
||||
<li>Wrap multi-line values, font size.</li>
|
||||
<li>Date and date-time formats + locale (Moment.js).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Cover</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Source: none / first image in the post / cover property.</li>
|
||||
<li>Style (borderless / with border), aspect ratio, orientation, fit, position on the card.</li>
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Is it true about the hard-coded parameters? If not, replace it with the real reason for moving them
|
||||
to the settings: user requests, multiple databases with different structures, whatever.
|
||||
</p>
|
||||
<p>
|
||||
Preliminary answer: Yes, the first version was tailored to my database; the settings were added when
|
||||
I needed to make the plugin available externally. I’ll check and fix it.
|
||||
</p>
|
||||
</div>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">💡</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
I implemented the split preview just like in Obsidian itself: left-click reuses the panel, Ctrl+click opens
|
||||
a new tab within the split. Without this, on a wide screen, it’s inconvenient to
|
||||
view cards next to the board.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<h3>Works within the standard toolbar</h3>
|
||||
<p class="section__prose">
|
||||
The view hooks into the BasesView framework, so sorting, filtering, properties, and search from
|
||||
the Bases toolbar remain functional. The plugin only renders the query results; the data is not
|
||||
duplicated and does not depend on a separate storage.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/card-columns-obsidian/view-configure.webp" alt="Configure view popover with card and column width settings" width="1280" height="1183" loading="lazy" decoding="async" data-image-viewer />
|
||||
<img src="{{assetPrefix}}assets/card-columns-obsidian/view-configure.webp" alt="Columns view configuration screen" width="1280" height="1183" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Columns view settings</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="rezultat">
|
||||
<h2>The Result and How I Tested It</h2>
|
||||
<h2>Result: a board inside Obsidian Bases</h2>
|
||||
<p class="section__prose">
|
||||
This view solved my problem: a Bases query now reads like a board, rather than a flat stream
|
||||
of cards. Grouping by property + filtering by AND/OR tags—exactly what the default
|
||||
view was missing. Everything runs on the Bases query, so moving the vault and syncing don’t
|
||||
break anything.
|
||||
Card Columns keeps notes in Bases but changes how I scan them: I choose a grouping, filter tags,
|
||||
and open cards beside the board. When I need to change a status, dragging a card updates the same
|
||||
frontmatter property that forms the columns. I still use Columns with my own database; notes stay
|
||||
in the vault, so there is no separate board to keep in sync.
|
||||
</p>
|
||||
|
||||
<h3>Metrics: number of steps to filter</h3>
|
||||
<p class="section__prose">
|
||||
The main task I used to measure success: filter notes by two tags and find the right
|
||||
card. In the standard card view, this involves scrolling through the feed and scanning the titles with your eyes. In
|
||||
Columns, two clicks on the pills and the column is right in front of you.
|
||||
</p>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Can you run this test for real? Time 10 repetitions of the task: the default
|
||||
view versus Columns. Or count the exact number of steps.
|
||||
</p>
|
||||
<p>
|
||||
Preliminary answer: on a sample of 25 notes, filtering by two tags took about 40 seconds and
|
||||
required scrolling through the feed; in Columns, two clicks, about 5 seconds. These are rough estimates—
|
||||
replace them with actual measurements.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h3>Test: Long-term usability in daily work</h3>
|
||||
<p class="section__prose">
|
||||
The second criterion is more subjective, but for a tool tailored to my needs, it’s more important: will I still be
|
||||
using the plugin a month from now? I am—it’s become an integral part of my work with the database and doesn’t require
|
||||
me to remember how to use it.
|
||||
</p>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Are there any external indicators: installs, GitHub stars, reviews, or questions in the issue tracker? Any
|
||||
number confirming that you’re not the only one using the plugin.
|
||||
</p>
|
||||
<p>
|
||||
Preliminary answer: The plugin currently needs to be installed manually; it hasn’t been approved for the community repository yet, so
|
||||
there are only a handful of installs and no stars so far. If there’s actual data, include it here—
|
||||
it’s more convincing than any self-report.
|
||||
</p>
|
||||
</div>
|
||||
<p class="section__prose">
|
||||
What I’d do differently. I deliberately chose not to implement drag-and-drop of cards between columns,
|
||||
since that changes a property in the note, and for a view plugin, that poses a separate data integrity risk.
|
||||
But I see a demand for this among users, and I might add it as an optional mode. For
|
||||
now, since the plugin is maintained manually (it hasn’t been reviewed by the community directory yet), this is the only thing
|
||||
preventing users from using it right away.
|
||||
The screenshot shows my Links database; Obsidian displays 196 results. The plugin is listed in
|
||||
Obsidian Community. When I updated this case, the listing showed version 0.9.0 and 846 downloads;
|
||||
it supports Obsidian 1.8.0+, desktop and mobile, under the MIT license.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">✅</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
Main conclusion: a view for Bases only works when it respects
|
||||
the framework’s toolbar. I added a view, not a second storage system, and the notes
|
||||
remained regular notes.
|
||||
I care about the boundary between viewing and changing data. Grouping and filtering help me
|
||||
read the database; moving a card edits its property. In Columns, that action is visible and
|
||||
can be turned off.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Кейс: Card Columns, плагин-вид для Obsidian Bases. Показывает заметки как карточки, разложенные по колонкам, с фильтрацией тегов по И/ИЛИ."
|
||||
content="Как я создал Card Columns для Obsidian Bases: группировка заметок по свойствам, фильтрация тегов AND/OR и перенос карточек между колонками."
|
||||
/>
|
||||
<title>Card Columns, плагин для Obsidian Bases: кейс</title>
|
||||
<title>Card Columns для Obsidian Bases: кейс о канбан-виде</title>
|
||||
{{> head-links}}
|
||||
{{> head-plyr}}
|
||||
<style>
|
||||
@@ -48,72 +48,7 @@
|
||||
.case-article a:not(.btn) {
|
||||
color: var(--accent);
|
||||
}
|
||||
.case-article .case-brief {
|
||||
list-style: none;
|
||||
margin: 1.5rem 0 0;
|
||||
padding: 1.1rem 1.25rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
|
||||
gap: 0.85rem 1.5rem;
|
||||
font-size: 0.9rem;
|
||||
border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
|
||||
border-radius: var(--radius-md, 12px);
|
||||
}
|
||||
.case-article .case-brief li {
|
||||
margin: 0;
|
||||
}
|
||||
.case-article .case-brief span {
|
||||
display: block;
|
||||
margin-bottom: 0.15rem;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.case-article .case-todo {
|
||||
margin: 1rem 0 1.25rem;
|
||||
padding: 0.9rem 1.1rem;
|
||||
border-left: 2px solid var(--accent);
|
||||
background: color-mix(in srgb, var(--accent) 8%, transparent);
|
||||
border-radius: 0 var(--radius-sm, 8px) var(--radius-sm, 8px) 0;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
.case-article .case-todo p {
|
||||
margin: 0 0 0.5rem;
|
||||
}
|
||||
.case-article .case-todo p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.case-article .case-todo__q {
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
}
|
||||
.case-todo__label {
|
||||
display: block;
|
||||
margin-bottom: 0.35rem;
|
||||
font-size: 0.68rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--accent);
|
||||
opacity: 0.85;
|
||||
}
|
||||
.case-article details.case-details {
|
||||
margin: 0.75rem 0 1rem;
|
||||
padding: 0.6rem 0.9rem;
|
||||
border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
|
||||
border-radius: var(--radius-sm, 8px);
|
||||
}
|
||||
.case-article details.case-details > summary {
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
.case-article details.case-details[open] > summary {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.case-block {
|
||||
margin-top: 3rem;
|
||||
padding-top: 2.5rem;
|
||||
@@ -179,311 +114,137 @@
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">Obsidian Bases · Plugin</p>
|
||||
<h1 class="case-page__h1">
|
||||
Канбан-вид для Obsidian Bases,<br />который не трогает ваши заметки
|
||||
Канбан-доска для Obsidian Bases<br />с фильтрацией и перетаскиванием
|
||||
</h1>
|
||||
<p class="case-page__sub">
|
||||
Card Columns: заметки как карточки по колонкам,<br />
|
||||
отбор по тегам И/ИЛИ за два клика
|
||||
Card Columns: группировка по свойствам,<br />
|
||||
быстрый отбор тегов AND/OR
|
||||
</p>
|
||||
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/card-columns-obsidian/overview.webp" alt="База ссылок в Obsidian, сгруппированная по тегам в колонки Card Columns" width="2084" height="1296" loading="eager" decoding="async" data-image-viewer />
|
||||
<figcaption>База заметок, сгруппированная по тегам в Columns</figcaption>
|
||||
<figcaption>Links: 196 результатов в режиме Columns</figcaption>
|
||||
</figure>
|
||||
|
||||
<ul class="case-brief">
|
||||
<li><span>Роль</span>Продуктовый дизайн и разработка</li>
|
||||
<li><span>Платформа</span>Obsidian Bases</li>
|
||||
<li><span>Статус</span>Рабочий плагин в <a href="https://community.obsidian.md/plugins/card-columns" target="_blank" rel="noopener noreferrer">каталоге плагинов Obsidian</a>, open source (MIT)</li>
|
||||
<li><span>Команда</span>Соло, пет-проект</li>
|
||||
<li><span>Срок</span>Черновой ответ, заменить</li>
|
||||
</ul>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<p class="case-todo__q">
|
||||
Сколько заняла работа от первой идеи до рабочей версии? Недели? Месяц выходных?
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: собрал за три недели вечером, потом ещё месяц доводил по ходу
|
||||
собственной работы. Заменить на реальное.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="section__prose">
|
||||
В Obsidian появились Bases, отдельный тип файла, который показывает заметки не текстом, а
|
||||
в разных видах: таблицей, карточками, деревом. Стандартный вид карточек мне не зашёл: он
|
||||
плоский, без группировки, и в нём не разобраться, когда заметок сотни. Я хотел видеть их
|
||||
раскладку по колонкам, как канбан, но без лишнего веса. Так появился плагин-вид Card Columns.
|
||||
Card Columns - мой плагин-вид для Obsidian Bases. Я спроектировал и разработал его сам:
|
||||
хотел видеть заметки колонками, а не искать нужные в длинной ленте штатного Cards. Плагин
|
||||
опубликован в <a href="https://community.obsidian.md/plugins/card-columns" target="_blank" rel="noopener noreferrer">каталоге Obsidian Community</a>,
|
||||
исходный код открыт по лицензии MIT.
|
||||
</p>
|
||||
|
||||
<div class="case-block" id="kontekst">
|
||||
<h2>Контекст</h2>
|
||||
<h2>От запроса Bases к колонкам</h2>
|
||||
<p class="section__prose">
|
||||
Bases, это не заметка и не отдельная база данных. Это запрос к vault-у: выбираешь
|
||||
заметки по фильтру, и фреймворк рисует их в выбранном виде. У самого Obsidian есть
|
||||
встроенный вид карточек, но он одноплановый: нет группировки по свойствам, нет
|
||||
нормальной фильтрации. Я решил сделать свой вид, который встраивается в переключатель
|
||||
Bases наравне со штатными.
|
||||
Файл <code>.base</code> описывает запрос к заметкам в vault: какие записи показать и какие
|
||||
свойства вывести. Штатный вид Cards в моей базе складывал результаты в длинную ленту.
|
||||
Я хотел видеть ту же выборку по группам, например по статусу или тегу.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Главное ограничение было в самом фреймворке: плагин не хранит данные, а рисует то, что
|
||||
выдал Bases-запрос (Sort, Filter, Properties, Search из тулбара). Значит, вся логика
|
||||
выборки остаётся на Bases, а моя задача, только представление и навигация по нему.
|
||||
Columns подключается как ещё один BasesView и получает результат запроса. Сортировка,
|
||||
фильтры, набор свойств и поиск остаются за штатным тулбаром. Я не стал заводить отдельную
|
||||
доску: заметки и настройки запроса остаются в Bases, плагин меняет только их представление.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="pochemu-svoi">
|
||||
<h2>Почему не готовое</h2>
|
||||
<div class="case-block" id="filtry">
|
||||
<h2>Сначала сгруппировать, потом отобрать</h2>
|
||||
<p class="section__prose">
|
||||
Прежде чем писать код, я посмотрел, что уже есть. Три пути, все мимо:
|
||||
Группировку настраиваю через Group by в тулбаре Bases: по тегу, статусу, категории или
|
||||
любому frontmatter-свойству. Если свойство не задано, Columns группирует по тегам. Колонки
|
||||
строятся из значений выбранного свойства, а исходный запрос остаётся тем же. Одна база
|
||||
подходит для разных разрезов: меняю только группировку.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<strong>Штатный вид карточек Bases.</strong> Рисует ровный поток карточек без группировки.
|
||||
Когда заметок за сотню, это лента, в которой нужно скроллить и вглядываться в заголовки.
|
||||
Отпал первым.
|
||||
Теги для быстрого отбора вынесены отдельными пилюлями под тулбаром. Щёлкнул один раз,
|
||||
оставил этот тег. Выбрал следующий, добавил его по OR. Для точного переключения использую
|
||||
Ctrl+клик или правую кнопку мыши, а кнопкой OR/AND меняю логику отбора:
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<strong>Канбан-плагины из комьюнити.</strong> Большинство тянет за собой свою систему
|
||||
хранения: доска живёт отдельно от vault-а, заметки дублируются. Получается вторая база,
|
||||
которую надо синхронизировать. Мне это было не нужно.
|
||||
Эти пилюли не заменяют Filter в тулбаре. Bases формирует исходную выборку, а теговый фильтр
|
||||
сужает её уже внутри Columns. Так я не меняю запрос, когда нужно быстро посмотреть подмножество.
|
||||
</p>
|
||||
<ul class="section__prose">
|
||||
<li>первый тег оставляет только заметки с ним;</li>
|
||||
<li>следующий добавляет заметки с любым из выбранных тегов;</li>
|
||||
<li>Ctrl+клик или правый клик добавляет и снимает один тег, не сбрасывая остальные;</li>
|
||||
<li>OR/AND переключает условие между «любой из» и «все выбранные», All очищает выбор.</li>
|
||||
</ul>
|
||||
<p class="section__prose">
|
||||
<strong>Соседний bases-kanban.</strong> Ближайший по духу: цепляется к Bases, делает
|
||||
канбан. Но он пишет в заметки: перетаскивание карточки меняет frontmatter. Для view-плагина
|
||||
это риск, о котором ниже.
|
||||
Фильтр остаётся перед глазами вместе с доской. Модальное окно здесь только мешало бы:
|
||||
пришлось бы закрывать его, чтобы проверить результат.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">📌</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
Отказ от drag-and-drop, это не недоделка, а позиция. Плагин представления не должен
|
||||
писать в пользовательские данные. Это решение определило всё остальное.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<p class="case-todo__q">
|
||||
Ты реально ставил и тестировал чужие плагины или ориентировался по описаниям? Какие
|
||||
именно смотрел?
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: поставил три штуки, погонял неделю на своей базе, удалил. bases-kanban
|
||||
смотрел в исходниках, не ставил. Заменить на реальное, названия плагинов вписать.
|
||||
</p>
|
||||
</div>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/card-columns-obsidian/filter-use.webp" alt="Теги-фильтры над колонками карточек Card Columns" width="1280" height="796" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Фильтры тегов остаются рядом с колонками</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="zadacha">
|
||||
<h2>Задача</h2>
|
||||
<div class="case-block" id="kartochki">
|
||||
<h2>Карточка показывает нужные поля</h2>
|
||||
<p class="section__prose">
|
||||
Спроектировать вид для Bases, который показывает заметки карточками по колонкам и позволяет
|
||||
быстро отбирать нужное. Жёсткое ограничение: плагин ничего не пишет в заметки и не хранит
|
||||
своего состояния, а сортировка, фильтр, свойства и поиск из штатного тулбара Bases должны
|
||||
работать как раньше.
|
||||
Состав карточки задаётся штатным списком Properties. Первое выбранное свойство становится
|
||||
заголовком, остальные отображаются чипами: текст, теги, ссылки, булевы значения и даты.
|
||||
Для чипов можно выбрать вертикальный стек или компактную сетку, настроить перенос и формат даты.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Если базе нужны обложки, Columns возьмёт первую картинку из заметки или значение указанного
|
||||
frontmatter-свойства. Можно настроить пропорции (Auto, 1:1, 3:2, 4:3 или 16:9), вписывание
|
||||
и место обложки. Карточка открывается в активной панели, модальном окне, новой вкладке или
|
||||
сплите. В сплите обычный клик переиспользует панель, Ctrl+клик открывает новую вкладку.
|
||||
Так можно читать заметку рядом с доской и не терять контекст выборки.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">📌</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
Главный риск, сделать вид, который конфликтует со штатным тулбаром Bases. Тогда
|
||||
пользователь теряет сортировку и поиск, ради которых Bases и берут. Этого нельзя
|
||||
было допустить.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="reshenie">
|
||||
<h2>Решения</h2>
|
||||
<h2>Перетаскивание меняет свойство заметки</h2>
|
||||
<p class="section__prose">
|
||||
Плагин добавляет в Bases вид «Columns». Карточки строятся из результатов Bases-запроса,
|
||||
группировка задаётся свойством, а отбор, кликабельными тегами. Дальше, пять выборов,
|
||||
которые определили результат. В каждом есть то, от чего я отказался.
|
||||
</p>
|
||||
<!-- МЕДИА: скриншот вида с колонками и карточками внутри.
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../assets/card-columns-obsidian/board.webp" alt="Колонки карточек с группировкой по свойству" width="1920" height="1080" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Вид с колонками</figcaption>
|
||||
</figure>
|
||||
-->
|
||||
|
||||
<h3>Группировка по любому свойству</h3>
|
||||
<p class="section__prose">
|
||||
Колонки формируются из Group by в тулбаре Bases, по тегу, статусу, категории или любому
|
||||
frontmatter-свойству. Меняешь свойство в запросе, и доска пересобирается сама. Так одна
|
||||
и та же база закрывает разные разрезы: проекты по статусу, заметки по тегам, задачи по
|
||||
приоритету.
|
||||
</p>
|
||||
|
||||
<h3>Фильтр тегов по И и ИЛИ</h3>
|
||||
<p class="section__prose">
|
||||
Это то, ради чего плагин и задумывался. Под тулбаром, пилюли тегов, по клику они
|
||||
отсеивают карточки по всем колонкам сразу:
|
||||
</p>
|
||||
<ul class="section__prose">
|
||||
<li>Левый клик по тегу, показать только его (сбрасывает остальные фильтры).</li>
|
||||
<li>Левый клик по следующему тегу, показать заметки с ЛЮБЫМ из выбранных (режим ИЛИ).</li>
|
||||
<li>Ctrl+Клик или правый клик, переключить тег, не сбрасывая выбор.</li>
|
||||
<li>Кнопка OR/AND, переключить между «любой из» и «все перечисленные» для нескольких тегов.</li>
|
||||
<li>All, снять все фильтры.</li>
|
||||
</ul>
|
||||
<p class="section__prose">
|
||||
Связка «ИЛИ-добавление левым кликом + точный toggle через Ctrl» получилась интуитивной:
|
||||
быстрый отбор не сбивает то, что уже выбрано. Альтернативу, вынести фильтр в модалку,
|
||||
отверг сразу: лишний клик и потеря контекста того, что уже отфильтровано.
|
||||
В релизе 0.9.0 карточку можно перетащить в другую колонку, и Columns обновит
|
||||
frontmatter-свойство, по которому построена группировка, через API
|
||||
Obsidian <code>processFrontMatter()</code>. Если колонки собраны по статусу, после переноса
|
||||
меняется именно статус заметки. Если в свойстве несколько значений, старое убирается,
|
||||
новое добавляется, остальные сохраняются.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Выбор здесь не в самой фиче, а в том, где она живёт. Я выбрал пилюли под тулбаром вместо
|
||||
отдельного окна фильтров, потому что отбор по тегам, это действие на каждом шаге работы
|
||||
с базой. Модалка превращает его в прерванный сценарий: открыл, настроил, закрыл, проверил.
|
||||
Пилюли оставляют результат перед глазами, а состояние фильтра видно всегда.
|
||||
Я оставил этот сценарий настраиваемым. Drag-and-drop включён по умолчанию, но его можно
|
||||
отключить в General. Так пользователь сам выбирает: только смотреть на группы или менять
|
||||
значение свойства прямо с доски.
|
||||
</p>
|
||||
<h3>Настройки под разные базы</h3>
|
||||
<p class="section__prose">
|
||||
У вида четыре группы настроек: General, Title, Properties и Cover. В них задаются ширина
|
||||
карточек, число колонок внутри группы (от 1 до 6), порядок колонок, зебра и masonry.
|
||||
Порядок можно оставить автоматическим или задать вручную; пустые колонки в этом списке
|
||||
сохраняются. Сетка показывает несколько карточек рядом, masonry заполняет вертикальные
|
||||
пустоты, а зебра помогает не сбиться при чтении широкой доски. Отдельно настраиваются заголовки, чипы, даты
|
||||
и обложки. Один вид подстраивается под разные базы, а не наоборот.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/card-columns-obsidian/filter-use.webp" alt="Панель тегов для фильтрации карточек в Card Columns" width="1280" height="796" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Фильтрация карточек по тегам</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Карточки и обложки</h3>
|
||||
<p class="section__prose">
|
||||
По каждой заметке рисуются свойства как чипы, текст, теги, ссылки, булевы, даты. Можно
|
||||
показать обложку: из первой картинки в заметке или из отдельного свойства. У обложки
|
||||
полный контроль, соотношение сторон (Auto, 1:1, 3:2, 4:3, 16:9), рамка, вписывание
|
||||
(cover/contain), ориентация и место на карточке (над заголовком, под ним, после всего).
|
||||
</p>
|
||||
|
||||
<h3>Решение: настройки вынесены из кода</h3>
|
||||
<p class="section__prose">
|
||||
Сначала параметры были захардкожены под мою базу. Это ошибка: вид перестал бы работать
|
||||
для чужого сценария. Вынес всё в gear-меню, разбив на четыре секции, чтобы вид
|
||||
подстраивался под разные базы, а не под мой единственный случай. Больше 15 параметров.
|
||||
</p>
|
||||
<details class="case-details">
|
||||
<summary>Показать полный список настроек</summary>
|
||||
<p class="section__prose"><strong>General</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Куда открывать карточку: активная панель, всплывающее окно, новая вкладка, сплит вправо / вниз.</li>
|
||||
<li>Ширина карточки (px).</li>
|
||||
<li>Колонок в группе (1–6), сетка внутри колонки.</li>
|
||||
<li>Зебра колонок (чередование фона для сканирования).</li>
|
||||
<li>Masonry-раскладка (карточки заполняют вертикальные пустоты).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Title</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Перенос заголовка, жирный заголовок, размер шрифта (px).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Properties</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Раскладка чипов: стек (вертикально) или сетка (компактно в строку).</li>
|
||||
<li>Перенос многострочных значений, размер шрифта.</li>
|
||||
<li>Формат даты и даты-времени + локаль (Moment.js).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Cover</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Источник: нет / первая картинка в заметке / свойство-обложка.</li>
|
||||
<li>Стиль (без рамки / с рамкой), соотношение сторон, ориентация, вписывание, позиция на карточке.</li>
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<p class="case-todo__q">
|
||||
Это правда про захардкоженные параметры? Если нет, замени на реальную причину выноса
|
||||
в настройки: просьбы пользователей, несколько баз с разной структурой, что угодно.
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: да, первая версия была под мою базу, настройки появились, когда
|
||||
понадобилось открыть плагин наружу. Проверить и поправить.
|
||||
</p>
|
||||
</div>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">💡</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
Сплит-превью сделал как в самом Obsidian: левый клик переиспользует панель, Ctrl+Клик,
|
||||
новую вкладку внутри сплита. Без этого на широком экране карточки неудобно
|
||||
просматривать рядом с доской.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<h3>Работает внутри штатного тулбара</h3>
|
||||
<p class="section__prose">
|
||||
Вид цепляется к BasesView-фреймворку, поэтому сортировка, фильтр, свойства и поиск из
|
||||
тулбара Bases остаются рабочими. Плагин только рисует результат запроса, данные не
|
||||
дублируются и не зависят от отдельного хранилища.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/card-columns-obsidian/view-configure.webp" alt="Окно настройки вида Columns с параметрами карточек и ширины колонок" width="1280" height="1183" loading="lazy" decoding="async" data-image-viewer />
|
||||
<img src="{{assetPrefix}}assets/card-columns-obsidian/view-configure.webp" alt="Экран настройки вида Columns" width="1280" height="1183" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Настройки вида Columns</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="rezultat">
|
||||
<h2>Результат и как я это мерял</h2>
|
||||
<h2>Результат: доска внутри Obsidian Bases</h2>
|
||||
<p class="section__prose">
|
||||
Вид закрыл мою боль: Bases-запрос теперь читается как доска, а не как плоская лента
|
||||
карточек. Группировка по свойству + отбор по тегам И/ИЛИ, то, чего не хватало штатному
|
||||
виду. Всё крутится на запросе Bases, так что перенос vault-а и синхронизация ничего не
|
||||
ломают.
|
||||
Card Columns оставляет заметки в Bases, но меняет способ их обзора: я задаю группировку,
|
||||
отбираю теги и открываю карточки рядом с доской. Когда нужна смена статуса, перетаскивание
|
||||
правит то же frontmatter-свойство, по которому строятся колонки. Я продолжаю пользоваться
|
||||
Columns в своей базе: заметки остаются в vault, отдельную доску синхронизировать не нужно.
|
||||
</p>
|
||||
|
||||
<h3>Замер: сколько действий на отбор</h3>
|
||||
<p class="section__prose">
|
||||
Главная задача, по которой я мерял успех: отобрать заметки по двум тегам и найти нужную
|
||||
карточку. В штатном виде карточек это скролл ленты с поиском по заголовкам глазами. В
|
||||
Columns, два клика по пилюлям и колонка перед глазами.
|
||||
</p>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<p class="case-todo__q">
|
||||
Можешь прогнать этот замер по-настоящему? Засечь время на 10 повторах задачи: штатный
|
||||
вид против Columns. Или посчитать точное число действий.
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: на выборке из 25 заметок отбор по двум тегам занимал около 40 секунд и
|
||||
требовал скроллить ленту; в Columns, два клика, примерно 5 секунд. Цифры примерные,
|
||||
заменить на замеренные.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h3>Замер: живучесть в ежедневной работе</h3>
|
||||
<p class="section__prose">
|
||||
Второй критерий субъективнее, но для инструмента под себя он важнее: продолжаю ли я
|
||||
пользоваться плагином через месяц. Пользуюсь, он встроился в работу с базой и не требует
|
||||
вспоминать, как им управлять.
|
||||
</p>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<p class="case-todo__q">
|
||||
Есть ли внешние сигналы: установки, звёзды на GitHub, отзывы, вопросы в issue? Любая
|
||||
цифра, подтверждающая, что плагином пользуются не только ты.
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: плагин пока ставится вручную, через каталог комьюнити не прошёл, так
|
||||
что установок единицы и звёзд пока нет. Если есть реальные данные, вписать их сюда,
|
||||
это сильнее любого-self-report.
|
||||
</p>
|
||||
</div>
|
||||
<p class="section__prose">
|
||||
Что сделал бы иначе. Drag-and-drop карточек между колонками не стал делать сознательно,
|
||||
это меняет свойство в заметке, и для view-плагина это отдельный риск целостности данных.
|
||||
Но вижу запрос на это у пользователей, и, возможно, добавлю как опциональный режим. А
|
||||
пока плагин живёт вручную (через community-каталог ещё не прошёл), это единственное, что
|
||||
мешает им пользоваться сходу.
|
||||
На скриншоте моя база Links: Obsidian показывает 196 результатов. Плагин уже опубликован
|
||||
в каталоге Obsidian Community. На момент обновления кейса там указаны версия 0.9.0 и
|
||||
846 загрузок; поддерживаются Obsidian 1.8.0+, Desktop и Mobile, лицензия MIT.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">✅</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
Главный вывод: вид для Bases получается рабочим только тогда, когда он уважает
|
||||
тулбар фреймворка. Я добавил представление, а не вторую систему хранения, и заметки
|
||||
остались обычными заметками.
|
||||
Для меня важна граница между обзором и изменением данных. Группировка и фильтр помогают
|
||||
читать базу; перенос карточки меняет её свойство. В Columns это действие видно и его
|
||||
можно отключить.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
@@ -1,115 +1,72 @@
|
||||
# Card Columns — плагин-вид для Obsidian Bases
|
||||
# Card Columns для Obsidian Bases
|
||||
|
||||
- **Источник:** `public/cases/card-columns-obsidian/index.html`
|
||||
- **Источник:** `src/pages/cases/card-columns-obsidian.html`
|
||||
- **eyebrow:** Obsidian Bases · Plugin
|
||||
- **meta description:** Кейс: Card Columns, плагин-вид для Obsidian Bases. Показывает заметки как карточки, разложенные по колонкам, с фильтрацией тегов по И/ИЛИ.
|
||||
- **meta description:** Как я создал Card Columns для Obsidian Bases: группировка заметок по свойствам, фильтрация тегов AND/OR и перенос карточек между колонками.
|
||||
|
||||
---
|
||||
## Канбан-доска для Obsidian Bases с фильтрацией и перетаскиванием
|
||||
|
||||
**Заметка по путям к медиа:** файлы кладутся в `public/assets/card-columns-obsidian/`, в разметке страницы пути `../assets/card-columns-obsidian/файл.webp`. Форматы: WebP (изображения, постеры), WebM + MP4 (видео).
|
||||
Card Columns: группировка по свойствам, быстрый отбор тегов AND/OR.
|
||||
|
||||
## Brief (блок метаданных на странице)
|
||||
На скриншоте моя база Links: Obsidian показывает 196 результатов.
|
||||
|
||||
- **Роль:** Продуктовый дизайн и разработка
|
||||
- **Платформа:** Obsidian Bases
|
||||
- **Статус:** Рабочий плагин в [каталоге плагинов Obsidian](https://community.obsidian.md/plugins/card-columns), open source (MIT)
|
||||
- **Команда:** Соло, пет-проект
|
||||
Card Columns - мой плагин-вид для Obsidian Bases. Я спроектировал и разработал его сам: хотел видеть заметки колонками, а не искать нужные в длинной ленте штатного Cards. Плагин опубликован в [каталоге Obsidian Community](https://community.obsidian.md/plugins/card-columns), исходный код открыт по лицензии MIT.
|
||||
|
||||
## Введение
|
||||
## От запроса Bases к колонкам
|
||||
|
||||
В Obsidian появились Bases, отдельный тип файла, который показывает заметки не текстом, а в разных видах: таблицей, карточками, деревом. Стандартный вид карточек мне не зашёл: он плоский, без группировки, и в нём не разобраться, когда заметок сотни. Я хотел видеть их раскладку по колонкам, как канбан, но без лишнего веса. Так появился плагин-вид Card Columns.
|
||||
Файл `.base` описывает запрос к заметкам в vault: какие записи показать и какие свойства вывести. Штатный вид Cards в моей базе складывал результаты в длинную ленту. Я хотел видеть ту же выборку по группам, например по статусу или тегу.
|
||||
|
||||
## Контекст
|
||||
Columns подключается как ещё один BasesView и получает результат запроса. Сортировка, фильтры, набор свойств и поиск остаются за штатным тулбаром. Я не стал заводить отдельную доску: заметки и настройки запроса остаются в Bases, плагин меняет только их представление.
|
||||
|
||||
Bases, это не заметка и не отдельная база данных. Это запрос к vault-у: выбираешь заметки по фильтру, и фреймворк рисует их в выбранном виде. У самого Obsidian есть встроенный вид карточек, но он одноплановый: нет группировки по свойствам, нет нормальной фильтрации. Я решил сделать свой вид, который встраивается в переключатель Bases наравне со штатными.
|
||||
## Сначала сгруппировать, потом отобрать
|
||||
|
||||
Главное ограничение было в самом фреймворке: плагин не хранит данные, а рисует то, что выдал Bases-запрос (Sort, Filter, Properties, Search из тулбара). Значит, вся логика выборки остаётся на Bases, а моя задача, только представление и навигация по нему.
|
||||
Группировку настраиваю через Group by в тулбаре Bases: по тегу, статусу, категории или любому frontmatter-свойству. Если свойство не задано, Columns группирует по тегам. Колонки строятся из значений выбранного свойства, а исходный запрос остаётся тем же. Одна база подходит для разных разрезов: меняю только группировку.
|
||||
|
||||
## Задача
|
||||
Теги для быстрого отбора вынесены отдельными пилюлями под тулбаром. Щёлкнул один раз, оставил этот тег. Выбрал следующий, добавил его по OR. Для точного переключения использую Ctrl+клик или правую кнопку мыши, а кнопкой OR/AND меняю логику отбора:
|
||||
|
||||
Спроектировать и собрать view-плагин для Obsidian Bases: заметки из запроса показываются карточками, разложенными по колонкам, а по колонкам легко ориентироваться и отбирать нужное. Вид должен жить в переключателе Bases рядом со штатными и не ломать встроенный тулбар (сортировку, фильтр, поиск).
|
||||
Эти пилюли не заменяют Filter в тулбаре. Bases формирует исходную выборку, а теговый фильтр сужает её уже внутри Columns. Так я не меняю запрос, когда нужно быстро посмотреть подмножество.
|
||||
|
||||
> **Callout (📌):** Главный риск, сделать вид, который конфликтует со штатным тулбаром Bases. Тогда пользователь теряет сортировку и поиск, ради которых Bases и берут. Этого нельзя было допустить.
|
||||
- первый тег оставляет только заметки с ним;
|
||||
- следующий добавляет заметки с любым из выбранных тегов;
|
||||
- Ctrl+клик или правый клик добавляет и снимает один тег, не сбрасывая остальные;
|
||||
- OR/AND переключает условие между «любой из» и «все выбранные», All очищает выбор.
|
||||
|
||||
## Решение
|
||||
Фильтр остаётся перед глазами вместе с доской. Модальное окно здесь только мешало бы: пришлось бы закрывать его, чтобы проверить результат.
|
||||
|
||||
Плагин добавляет в Bases вид «Columns». Карточки строятся из результатов Bases-запроса, группировка задаётся свойством, а отбор, кликабельными тегами.
|
||||
## Карточка показывает нужные поля
|
||||
|
||||
### Группировка по любому свойству
|
||||
Состав карточки задаётся штатным списком Properties. Первое выбранное свойство становится заголовком, остальные отображаются чипами: текст, теги, ссылки, булевы значения и даты. Для чипов можно выбрать вертикальный стек или компактную сетку, настроить перенос и формат даты.
|
||||
|
||||
Колонки формируются из Group by в тулбаре Bases, по тегу, статусу, категории или любому frontmatter-свойству. Меняешь свойство в запросе, и доска пересобирается сама. Так одна и та же база закрывает разные разрезы: проекты по статусу, заметки по тегам, задачи по приоритету.
|
||||
Если базе нужны обложки, Columns возьмёт первую картинку из заметки или значение указанного frontmatter-свойства. Можно настроить пропорции (Auto, 1:1, 3:2, 4:3 или 16:9), вписывание и место обложки. Карточка открывается в активной панели, модальном окне, новой вкладке или сплите. В сплите обычный клик переиспользует панель, Ctrl+клик открывает новую вкладку. Так можно читать заметку рядом с доской и не терять контекст выборки.
|
||||
|
||||
### Фильтр тегов по И и ИЛИ
|
||||
## Перетаскивание меняет свойство заметки
|
||||
|
||||
Это то, ради чего плагин и задумывался. Под тулбаром, пилюли тегов, по клику они отсеивают карточки по всем колонкам сразу:
|
||||
В релизе 0.9.0 карточку можно перетащить в другую колонку, и Columns обновит frontmatter-свойство, по которому построена группировка, через API Obsidian `processFrontMatter()`. Если колонки собраны по статусу, после переноса меняется именно статус заметки. Если в свойстве несколько значений, старое убирается, новое добавляется, остальные сохраняются.
|
||||
|
||||
- Левый клик по тегу, показать только его (сбрасывает остальные фильтры).
|
||||
- Левый клик по следующему тегу, показать заметки с ЛЮБЫМ из выбранных (режим ИЛИ).
|
||||
- Ctrl+Клик или правый клик, переключить тег, не сбрасывая выбор.
|
||||
- Кнопка OR/AND, переключить между «любой из» и «все перечисленные» для нескольких тегов.
|
||||
- All, снять все фильтры.
|
||||
Я оставил этот сценарий настраиваемым. Drag-and-drop включён по умолчанию, но его можно отключить в General. Так пользователь сам выбирает: только смотреть на группы или менять значение свойства прямо с доски.
|
||||
|
||||
Связка «ИЛИ-добавление левым кликом + точный toggle через Ctrl» получилась интуитивной: быстрый отбор не сбивает то, что уже выбрано. Альтернативу, вынести фильтр в модалку, отверг сразу: лишний клик и потеря контекста того, что уже отфильтровано.
|
||||
### Настройки под разные базы
|
||||
|
||||
### Карточки и обложки
|
||||
У вида четыре группы настроек: General, Title, Properties и Cover. В них задаются ширина карточек, число колонок внутри группы (от 1 до 6), порядок колонок, зебра и masonry. Порядок можно оставить автоматическим или задать вручную; пустые колонки в этом списке сохраняются. Сетка показывает несколько карточек рядом, masonry заполняет вертикальные пустоты, а зебра помогает не сбиться при чтении широкой доски. Отдельно настраиваются заголовки, чипы, даты и обложки. Один вид подстраивается под разные базы, а не наоборот.
|
||||
|
||||
По каждой заметке рисуются свойства как чипы, текст, теги, ссылки, булевы, даты. Можно показать обложку: из первой картинки в заметке или из отдельного свойства. У обложки полный контроль, соотношение сторон (Auto, 1:1, 3:2, 4:3, 16:9), рамка, вписывание (cover/contain), ориентация и место на карточке (над заголовком, под ним, после всего).
|
||||
## Результат: доска внутри Obsidian Bases
|
||||
|
||||
### Что заведено в настройки
|
||||
Card Columns оставляет заметки в Bases, но меняет способ их обзора: я задаю группировку, отбираю теги и открываю карточки рядом с доской. Когда нужна смена статуса, перетаскивание правит то же frontmatter-свойство, по которому строятся колонки. Я продолжаю пользоваться Columns в своей базе: заметки остаются в vault, отдельную доску синхронизировать не нужно.
|
||||
|
||||
Всю внешнюю вариативность я вынел в gear-меню, разбив на четыре секции, чтобы вид подстраивался под разные базы, а не под мой единственный сценарий.
|
||||
Плагин опубликован в каталоге Obsidian Community. На момент обновления кейса там указаны версия 0.9.0 и 846 загрузок; поддерживаются Obsidian 1.8.0+, Desktop и Mobile, лицензия MIT.
|
||||
|
||||
**General**
|
||||
|
||||
- Куда открывать карточку: активная панель, всплывающее окно, новая вкладка, сплит вправо / вниз.
|
||||
- Ширина карточки (px).
|
||||
- Колонок в группе (1–6), сетка внутри колонки.
|
||||
- Зебра колонок (чередование фона для сканирования).
|
||||
- Masonry-раскладка (карточки заполняют вертикальные пустоты).
|
||||
|
||||
**Title**
|
||||
|
||||
- Перенос заголовка, жирный заголовок, размер шрифта (px).
|
||||
|
||||
**Properties**
|
||||
|
||||
- Раскладка чипов: стек (вертикально) или сетка (компактно в строку).
|
||||
- Перенос многострочных значений, размер шрифта.
|
||||
- Формат даты и даты-времени + локаль (Moment.js).
|
||||
|
||||
**Cover**
|
||||
|
||||
- Источник: нет / первая картинка в заметке / свойство-обложка.
|
||||
- Стиль (без рамки / с рамкой), соотношение сторон, ориентация, вписывание, позиция на карточке.
|
||||
|
||||
> **Callout (💡):** Сплит-превью сделал как в самом Obsidian: левый клик переиспользует панель, Ctrl+Клик, новую вкладку внутри сплита. Без этого на широком экране карточки неудобно просматривать рядом с доской.
|
||||
|
||||
### Работает внутри штатного тулбара
|
||||
|
||||
Вид цепляется к BasesView-фреймворку, поэтому сортировка, фильтр, свойства и поиск из тулбара Bases остаются рабочими. Плагин только рисует результат запроса, данные не дублируются и не зависят от отдельного хранилища.
|
||||
|
||||
## Результат
|
||||
|
||||
Вид закрыл мою боль: Bases-запрос теперь читается как доска, а не как плоская лента карточек. Группировка по свойству + отбор по тегам И/ИЛИ, то, чего не хватало штатному виду. Всё крутится на запросе Bases, так что перенос vault-а и синхронизация ничего не ломают.
|
||||
|
||||
Метрики у пет-проекта нет, и придумывать её не стану. Проверяю проще: юзабилити на себе в ежедневной работе. Критерий, сколько действий нужно, чтобы отобрать заметки по двум тегам и найти нужную карточку. В штатном виде карточек это был скролл ленты с ручным поиском по заголовкам; здесь, два клика по пилюлям и колонка перед глазами. Если бы замерял всерьёз, считал бы время на задачу на выборке из 20–30 заметок до и после, но на своей повседневной базе разница заметна и без секундомера.
|
||||
|
||||
Что сделал бы иначе. Drag-and-drop карточек между колонками не стал делать сознательно, это меняет свойство в заметке, и для view-плагина это отдельный риск целостности данных. Но вижу запрос на это у пользователей, и, возможно, добавлю как опциональный режим. А пока плагин живёт вручную (через community-каталог ещё не прошёл), это единственное, что мешает им пользоваться сходу.
|
||||
|
||||
> **Callout (✅):** Главный вывод: вид для Bases получается рабочим только тогда, когда он уважает тулбар фреймворка. Я добавил представление, а не вторую систему хранения, и заметки остались обычными заметками.
|
||||
Для меня важна граница между обзором и изменением данных. Группировка и фильтр помогают читать базу; перенос карточки меняет её свойство. В Columns это действие видно и его можно отключить.
|
||||
|
||||
## Медиа
|
||||
|
||||
| Файл | Что показывает | Источник |
|
||||
|---|---|---|
|
||||
| `overview.webp` | База заметок в режиме Columns, сгруппированная по тегам | `card-columns/images/overview.webp` |
|
||||
| `filter-use.webp` | Фильтрация карточек кликабельными тегами | `card-columns/images/filter use.webp` |
|
||||
| `view-configure.webp` | Настройка вида и ширины колонок | `card-columns/images/view configure.webp` |
|
||||
Изображения взяты из репозитория Card Columns и лежат в `public/assets/card-columns-obsidian/`:
|
||||
|
||||
- `overview.webp` - обзор базы Links;
|
||||
- `filter-use.webp` - фильтрация тегами;
|
||||
- `view-configure.webp` - настройки вида.
|
||||
|
||||
## Источники фактуры
|
||||
|
||||
- Репозиторий: `https://github.com/mamadaevv/card-columns` (лицензия MIT).
|
||||
- Каталог плагинов Obsidian: `https://community.obsidian.md/plugins/card-columns`.
|
||||
- Скриншоты взяты из `images/` репозитория Card Columns.
|
||||
- Все параметры кастомизации и логика фильтрации взяты из README репозитория.
|
||||
- Drag-and-drop в плагине **отсутствует**: он есть у соседнего `ewerx/obsidian-bases-kanban`, не путать.
|
||||
- Репозиторий Card Columns, версия `0.9.0`: `README.md`, `manifest.json`, `main.ts`.
|
||||
- Карточка плагина в [Obsidian Community](https://community.obsidian.md/plugins/card-columns): версия, совместимость и число загрузок.
|
||||
- Скриншот обзора показывает 196 результатов в базе Links.
|
||||
Reference in new issue
Block a user