В статье будет показан прототип системы дел, который реализован в Obsidian. Система в основном будет базироваться на идеях GTD.

Задачи будут создаваться в дневнике/журнале и агрегироваться в отдельных заметках с использованием плагина Tasks.

Система будет адаптирована для телефонов.

Статья написана для продвинутых юзеров Obsidian. Новичкам, конечно, с ней будет тяжеловато разобраться.

Структура статьи (оглавление)

Введение

наверх

Система является прототипом, т.к. она реализуется в среде Obsidian. Obsidian – это софт, который не специализирован под задачи.

Хотя если говорить глобально, то Obsidian вообще ни под что не специализирован.

Можно ещё сказать, что статья не про "как сделать систему дел в Obsidian", а про "смотрите, я тут немного поисследовал разные возможности и в процессе придумал вот такие-то штуки".

Сама статья устроена по такой логике: сначала я покажу основную идеи и приёмы, потом обобщу всё в одну панель, далее разные дополнения и финты, затем пример, в конце преимущества и недостатки.

Стоит отметить, что в статье будут часто встречаться куски кода. Из меня такой себе кодер. Если же вы напротив опытный программист и у вас вдруг начнут вытекать глаза, то соберите их обратно в глазницы и предложите более красивый, стройный и оптимальный код в комментариях.

Итак, начнём.

Общая структура задачи

наверх

Вся идея системы дел в Obsidian будет закручена вокруг мысли, что любую задачу можно записать следующим образом:

- [ ] prefixes content time/date
  • prefixes – определяют тип, категорию и прочие параметры задачи

  • content – текст задачи

  • time/date – время и дата выполнения задачи

Приведу сразу пример задачи:

- [ ] #task/waiting_for #category/household Попросить что-то выполнить у [[Титус|Титуса]] ? 12:00 ? 2024-03-14
  • #task/waiting_for #category/household – префикс

  • Попросить что-то выполнить у [[Титус|Титуса]] – контент

  • ? 12:00 ? 2024-03-14 – время и дата

В данной статье в качестве префикса будут использоваться именно теги.

Префиксы – тип задачи и категория

наверх

В качестве типов задач я буду частично использовать подход из GTD.

Так у меня будут следующие типы задач:

Тип задачи

Описание

? inbox

Инбокс

? next_action

Метка, говорящая "делай именно эту задачу"

1️⃣ one-off

Задача, которую можно сделать за один подход

? multistep

Проектная задача (имеющая подзадачи)

? waiting_for

Делегированная задача

? regular

Повторяющаяся задача

? idea

Идея или мимолётная заметка

? reference

Ссылка на ресурс, который нужно изучить и обработать

? someday

Когда-нибудь потом

Я сразу добавил эмодзи. Скоро вы поймете зачем они нужны.

Тип задачи будет задаваться вложенным тегом #task/.

типы задач – пример
- [ ] #task/idea Сделать платный vault в Obsidian
- [ ] #task/one-off Сходить к ветеринару
- [ ] #task/... ...

Теперь введём понятие "категории". В силу того, что данную систему я накрутил в своей основной базе, то категории у меня обычно выступают как сферы знаний. Для данной статьи я выберу всего две таких:

Категория

Описание

? knowledge_base

Отвечает за всё, что связано со знаниями, заметками и ресёрчем

? health

Отвечает за исследование общей проблемы здоровья и за моё здоровье в частности

Категория также будет задаваться вложенным тегом #category/.

категории задач – пример
- [ ] #category/knowledge_base Исследовать проблему внедрения системы дел в базу знаний
- [ ] #category/health Найти лекарство от рака

Возможно вы уже заметили, что префиксы занимают многовато места. Скоро я это исправлю.

Почему теги

наверх

Немного подробнее обсудим почему я выбрал теги в качестве префиксов. Если кратко, то потому что теги плюс-минус адекватно поддерживается самим Obsidian и плагином Tasks.

Несомненно можно было в качестве префиксов выбрать, например, ссылки на категории. Т.е. сделать что-то такое:

префикс в виде категории
- [ ] [[health|?]] Разработать лекарство от рака

Это бы решило проблему длинного префикса, но тогда бы появилась проблема поиска задач (попробуйте сейчас написать такой поисковый запрос, который бы точным образом находил все незавершённые задачи, содержащие ссылку на [[health]]*). Вдобавок запросы tasks стали бы весьма замороченными.

*Не уверен, но, по-моему, поисковый запрос должен как-то так выглядеть /- \[ \] .*?\[\[health(?:\|[^]]*)?\]\]/.

Можно ещё в качестве префикса выбрать просто эмодзи. Т.е. вот так делать:

- [ ] ? Разработать лекарство от рака

Это бы также решило проблему длины префикса. Поиск по задачам стал бы проще, но такой подход сложно интегрировать с основной базой знаний. Т.е. будет несколько затруднительно одновременно найти, например, все внутренние и внешние источники (references), которые принадлежали бы к одной категории и содержали одно ключевое слово. Вдобавок на телефоне эмодзи вводить тоже не очень удобно.

Короче говоря, в каждом способе были бы свои проблемы, которые пришлось бы как-то решать. В тегах этих проблем оказалось меньше, поэтому их я и выбрал.

Кстати есть вариант с символами внутри markdown-задачи:

- [h] Разработать лекарство от рака

Однако этот способ совсем плох, ибо он нарушает синтаксис markdown, его не любят некоторые темы и ещё этот метод одномерный (можно задать только тип задачи). Вдобавок Tasks хоть и провайдит такой метод маркировки задач, но сам при этом пока что не шибко полноценно его поддерживает.

Создание и обзор задач

наверх

Задачи я буду создавать в периодических заметках. Этот метод хорош тем, что не нужно ломать себе голову с тем куда пристроить задачи. Просто создаёшь дневную заметку: пишешь дневник/журнал, по ходу накидываешь задачи.

Добавление задачи

наверх

Начнём с базового утверждения.

Чтобы задача попала в систему дел, у неё должен появиться префикс.

Префикс можно прописать вручную. Однако это медленно, а на телефоне так вообще работать с текстом и что-то там прописывать не очень удобно.

Чтобы ускорить процесс создания задач, я написал довольно мудрёный шаблон для Templater.

Функционал этого шаблона сводится к следующему:

  1. Шаблон сделает из текста под курсором задачу. Префиксы же можно будет выбрать из выпадающих списков

Создание задачи

  1. Шаблон может менять префиксы у задачи, которая находится под курсором

Изменение префикса

  1. Шаблон может создавать задачи и менять префиксы массово

массовое изменение задач

По мне так быстрее способа добавления задач и не придумаешь, хех. Ещё этот шаблон будет чертовски удобен на телефоне.

шаблон для создание задачи
<%*
// get contents of line under cursor
const cmEditorAct = this.app.workspace.activeLeaf.view.editor;
const currentCursor = cmEditorAct.getCursor();
const currentLine = currentCursor.line;
const originLineContents = cmEditorAct.getLine(currentLine);
// or get selected contents
const lineSelection = await tp.file.selection()
let lineContents = ""
let isSelection = ""
if (lineSelection.length >= originLineContents.length) {
	lineContents = lineSelection;
	isSelection = true;
} else {
	lineContents = originLineContents;
	isSelection = false;
}

// set tags
const taskType = [
  "? inbox",
  "? idea",
  "1️⃣ one-off",
  "? multistep",
  "? next_action",
  "? reference",
  "? waiting_for",
  "? someday",
  "? regular",
];
const taskTags = taskType.map(function(value) {
  return "#task/" + value.replace(/^[^\s]*\s*/, "");
});
// tag selection
let taskTag = await tp.system.suggester(
  taskType,
  taskTags,
  false,
  "Task type",
);
if (taskTag == null) {
	taskTag = "";
}

// set category
const categories = [
	"? health",
	"?️ knowledge_base",
];
const categoryTags = categories.map(function(value) {
	  return "#category/" + value.replace(/^[^\s]*\s*/, "");
});
// category selection
let categoryTag = await tp.system.suggester(
  categories,
  categoryTags,
  false,
  "Category",
);
if (categoryTag == null) {
	categoryTag = "";
}
// temporary deletion of task mark
const taskRegex = /- \[ \] /g;
lineContents = lineContents.replace(taskRegex, "");

// converting urls to markdown links
const linkRegex =
  /(?![^[]*\])(https?:\/\/[^\s]+)|\[(.*?)\]\((https?:\/\/[^\s]+)\)/g;
lineContents = lineContents
  .replace(linkRegex, (match, p1, p2, p3) => {
    if (p2 && p3) {
      return `[${p2}](${p3})`;
    } else {
      const siteName = p1.match(/(?:https?:\/\/)?(?:w{3}\.)?([a-zA-Z0-9-]+)\.[a-zA-Z]{2,}(?:\.[a-zA-Z]{2,})?(?:\/\S*)?/,)[1];
      return `[${siteName}](${match})`;
    }
  })

// add or modify the tag/category
const tagRegex = new RegExp(taskTags.join("|"), "g");
const categoryRegex = new RegExp(categoryTags.join("|"), "g");

let finalTask = taskTag
let finalCategory = categoryTag 
let paragraphs = lineContents.split(/\n/);
let tabulation
for (let i = 0; i < paragraphs.length; i++) {
  if (paragraphs[i].trim() !== "") {
	  if (taskTag == "") {
		finalTask = (paragraphs[i].match(tagRegex) || [""])[0];
	}
	  if (categoryTag == "") {
		finalCategory = (paragraphs[i].match(categoryRegex) || [""])[0];
	}
	  tabulation = (/\t/.test(paragraphs[i])) ? paragraphs[i].match(/\t/g).join("") : "";
	  paragraphs[i] = paragraphs[i].replace(tagRegex, "").replace(categoryRegex, "").trim()
	  
	  paragraphs[i] = tabulation + "- [ ] " + finalTask + " " + finalCategory + " " + paragraphs[i];
  }
}
lineContents = paragraphs.join("\n");

// remove extra spaces
lineContents = lineContents.replace(/ +/g, " ");

// line modification
if (isSelection) {
	tR += lineContents
} else {
	cmEditorAct.replaceRange(
	  lineContents,
	  { line: currentLine, ch: 0 },
	  { line: currentLine, ch: originLineContents.length },
	);
}
%>

Задачи на сегодня и на последующие дни

наверх

Если вы пробовали плагин Tasks, то наверняка у вас эти запросы уже есть. Я лишь просто покажу свой вариант таких запросов.

запросы на сегодня

Due

due today
hide task count
hide due date

Scheduled

scheduled today
hide task count
hide scheduled date

Overdue

(due before today) OR (scheduled before today)
not done
hide task count

запросы на последующие дни

Tomorrow

not done
(due tomorrow) OR (scheduled tomorrow)
group by function reverse task.scheduled.format("%%%%") ? "⌛ Scheduled:" : "? Due:"
hide task count
hide scheduled date
hide due date

Upcoming (after tomorrow)

not done
(due after tomorrow) OR (scheduled after tomorrow)
group by function task.happens.format("YYYY-MM-DD")
hide task count
hide due date
hide recurrence rule

Группирование задач

наверх

Теперь перейдём к самом интересному. К группированию задач.

Общая идея

наверх

В типах задач, мы можем сгруппировать по категориям.

В категориях по типам.

В этом и заключается основная идея группировки.

В силу того, что мы уже и так промаркировали задачи, нам остаётся только сделать правильные запросы Tasks.

Группирование в статусах по категориям

наверх

Все запросы для статусов будут выглядеть одинаково, за исключением одной строки.

Пример запроса выглядит вот так (для задач со статусом ? next_action):

not done
tags include #task/next_action 
group by function task.tags.filter( (tag) => tag.includes("#category/") ).map( (tag) => tag.split('/')[1] ? tag.split('/').slice(1, 2) : '')
sort by function task.happens.format("YYYY-MM-DD")
hide task count
hide tags

Разберём построчно:

  • not done

    • Отобрать незавершённые задачи

  • tags include #task/next_action

    • Отобрать задачи, которые содержат тег #task/next_action

    • Эту строку нужно будет менять в зависимости от статуса

  • group by function task.tags.filter( (tag) => tag.includes("#category/") ).map( (tag) => tag.split('/')[1] ? tag.split('/').slice(1, 2) : '')

    • group by function task.tags

      • сгруппировать по тегам

    • .filter( (tag) => tag.includes("#category/") )

      • но не по всем, а только по тем, которые содержат #category/

    • .map( (tag) => tag.split('/')[1] ? tag.split('/').slice(1, 2) : '')

      • сгруппировать только по той части, что идёт после #category/

      • это будет название самой категории (например, ? knowledge_base)

  • sort by function task.happens.format("YYYY-MM-DD")

    • отсортировать задачи внутри групп так, чтобы сначала показывались более близкие по времени

  • hide task count

    • скрыть количество задач

  • hide tags

    • скрыть теги в задачах

    • зачем их повторять, если мы и так по ним группируем?

Возможно я чутка перемудрил с функцией группировки. Если вы знаете как написать проще, то расскажите об этом в комментариях.

пример вывода запроса для статуса #task/next_action
Выглядит вроде как очень понятно и чисто
Выглядит вроде как очень понятно и чисто

CSS-сниппет, чтобы поменять обратную ссылку на иконку ?.

Для всех остальных статусов нужно будет поменять только строку с tags include и результат будет такой же.

Группирование в категориях по статусам

наверх

Логика группирующего запроса будет точно такой же.

Сам запрос выглядит вот так:

not done
tags include #category/knowledge_base
group by function task.tags.filter( (tag) => tag.includes("#task/") ).map( (tag) => tag.split('/')[1] ? tag.split('/').slice(1, 2) : '')
hide task count
hide tags

Единственная особенность, что теперь мы сначала отберём задачи с категорией, а потом уже сгруппируем по статусам.

пример вывода запроса для категории #category/knowledge_base

Порядок отображения групп

наверх

На мой взгляд, статусы лучше отобразить в порядке их значимости.

В документации Tasks, к сожалению, нет красивого способа задания порядка для отображаемых групп. При этом классические способы сортировки у меня почему-то не сработали. В общем пришлось эту проблему решить весьма громоздкими способами.

Решений будет два:

1. Ручной метод
not done 
tags include category/knowledge_base
group by function \
  if (task.tags.includes("#task/inbox"))         return "%%01%% ? [[_inbox|Inbox]]"; \
  if (task.tags.includes("#task/next_action"))   return "%%02%% ? Next Action"; \
  if (task.tags.includes("#task/one-off"))       return "%%03%% 1️⃣ One-off"; \
  if (task.tags.includes("#task/multistep"))     return "%%04%% ? Multistep"; \
  if (task.tags.includes("#task/waiting_for"))   return "%%05%% ? Waiting for"; \
  if (task.tags.includes("#task/regular"))       return "%%06%% ? Regular"; \
  if (task.tags.includes("#task/someday"))       return "%%07%% ? Someday"; \
  if (task.tags.includes("#task/idea"))          return "%%08%% ? Idea"; \
  if (task.tags.includes("#task/reference"))     return "%%09%% ? Reference"; \
  return "%%00%% Without status";
hide task count
hide tags

2. Слегка автоматизированный метод
not done 
tags include category/knowledge_base
group by function \
  const order = ["#task/inbox", \
				 "#task/next_action", \
				 "#task/one-off", \
				 "#task/multistep", \
				 "#task/waiting_for", \
				 "#task/regular", \
				 "#task/someday", \
				 "#task/idea", \
				 "#task/reference"]; \
   for (let i = 0; i < order.length; i++) {  \
     if (task.tags.includes(order[i])) { return  "%%" + i + "%% " + order[i].replace("#task/", "") } \
    }; \
   return "%%_%% Without status";
hide task count
hide tags

Результат вывода ручного метода:

вывод запроса для категории
И симпатично, и информативно
И симпатично, и информативно

Проблемка с вложенными задачами

наверх

Как понять, что задача является подзадачей? В task-менеджерах это всегда так или иначе обозначено и поддерживается это автоматически.

В нашем же случае есть по сути два варианта как показать, что задача является подзадачей.

  1. Указать это явно

- [ ] #task/multistep Основная задача
	- [ ] ⤵️ Подзадача 1
	- [ ] ⤵️ Подзадача 2
  1. Воспользоваться функцией связанных задач

- [ ] #task/multistep Основная задача ? abcdef
	- [ ] Подзадача 1 ⛔ abcdef
	- [ ] Подзадача 2 ⛔ abcdef

В итоге, конечно, суть не шибко отличается – что там определённые эмодзи в задачи, что там, хах.

Кстати, функция связанных задач довольно странно работает. Чтобы она корректно отрабатывала, нужно указать связь именно так, как я показал на скрине, а не так, как объясняется в документации.

Вообще... Я думаю, что на эту проблему можно отчасти забить, ибо она решается автоматически, если рабочий процесс подразумевает обзор задач. Я имею в виду то, что если подзадача была выполнена и при этом проигнорировано, что она является частью какого-то проекта, то ничего страшного не случится. На следующем обзоре так или иначе в проект допишутся и промаркируются новые задачи.

Если вы знаете другие способы указания, что задача является подзадачей, то напишите о них в комментариях.

Изменение отображения тегов

наверх

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

Решить проблему длины тегов можно несколькими способами.

  • 1-ый вариант – сделать сами теги короче

Вместо

- [ ] #task/multistep ...

можно использовать сокращения (так делает, например, этот юзер)

- [ ] #t/m ...

или вообще сделать одиночный тег

- [ ] #multi ...
или
- [ ] #m
или
- [ ] #?️ ...

Мне эти варианты не нравятся, т.к. подобные сокращения плохо считываются в принципе. Одиночные теги же мне не нравятся просто из-за своей неупорядоченности.

  • 2-ой вариант – изменить отображение определённых тегов

Идея в том, чтобы сохранить нормальные слова, которые будут поддерживать считываемую структуру, но при этом уплотнить визуально информацию.

Для этого можно заюзать следующий css-хак

tags.css
body {
  --color-of-statuses: rgba(162, 93, 53, 0.1);
  --color-of-categories: rgba(0, 255, 255, 0.1);
}

.tag[href="#task/multistep"],
.cm-tag-taskmultistep {
  font-size: 0px;
  padding: 0;
}

.tag[href="#task/multistep"]:after,
.cm-tag-taskmultistep:after,
 {
  font-size: var(--font-text-size);
}

.cm-active .tag[href="#task/multistep"],
.cm-active .cm-tag-taskmultistep,
.cm-hashtag-begin.cm-tag-taskmultistep:after {
  border-radius: 3px;
  background-color: var(--color-of-statuses);
  content: "?";
}

Суть его сводится к тому, чтобы #task/multistep отобразить как ?️.

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

В сниппете сделано так, чтобы на активной строке теги показывались полностью
В сниппете сделано так, чтобы на активной строке теги показывались полностью

Круто, да? Мы сохранили нормальные теги, но при этом смогли визуально уплотнить информацию.

А теперь о печальном. Сниппет сам по себе нетрудный. Однако статусов и категорий может быть много. К тому же с течением времени наверняка они будут как-то изменяться. Под каждое структурное новшество или изменение придется допиливать css-код. Вручную это делать ужасно скучно.

Эту проблему можно элегантно решить с помощью плагина. Как пилить плагины под Obsidian мне пока что было лень разбираться, поэтому я сделал временное/костыльное решение в виде Python-скрипта. В скрипте прописываются теги статусов и категорий, а также как их нужно отображать. В консоль выводится готовый css-код.

script.py
statuses = {
    "inbox": "?",
    "idea": "?",
    "one-off": "1️⃣",
    "multistep": "?",
    "next_action": "?",
    "reference": "?",
    "waiting_for": "?",
    "someday": "?",
    "regular": "?",
}
categories = {
    "knowledge_base": "?️",
    "health": "?",
}
print("body {\n  --color-of-statuses: rgba(162, 93, 53, 0.1);")
print("  --color-of-categories: rgba(0, 255, 255, 0.1);\n}")
print(
    """
/* ░█▀▀░▀█▀░█▀█░▀█▀░█░█░█▀▀ */
/* ░▀▀█░░█░░█▀█░░█░░█░█░▀▀█ */
/* ░▀▀▀░░▀░░▀░▀░░▀░░▀▀▀░▀▀▀ */
"""
)
statuses_result = ""
for key in statuses:
    if "_" in key:
        statuses_result = (
            statuses_result
            + f'.tag[href="#task/{key}"],\n'
            + f".cm-tag-task{key},\n"
            + f".cm-tag-task{key} + span.cm-hashtag,\n"
            + f".cm-tag-task{key} + span.cm-hashtag + .cm-hashtag,\n"
        )
    else:
        statuses_result = (
            statuses_result + f'.tag[href="#task/{key}"],\n' + f".cm-tag-task{key},\n"
        )
statuses_result = statuses_result[:-2]
statuses_result += """ {
  font-size: 0px;
  padding: 0;
}\n\n"""
for key in statuses:
    if "_" in key:
        statuses_result = (
            statuses_result
            + f'.tag[href="#task/{key}"]:after,\n'
            + f".cm-tag-task{key}:after,\n"
            + f".cm-tag-task{key} + span.cm-hashtag:after,\n"
            + f".cm-tag-task{key} + span.cm-hashtag + .cm-hashtag:after,\n"
        )
    else:
        statuses_result = (
            statuses_result
            + f'.tag[href="#task/{key}"]:after,\n'
            + f".cm-tag-task{key}:after,\n"
        )
statuses_result = statuses_result[:-2]
statuses_result += """ {
  font-size: var(--font-text-size);
}\n\n"""
for key in statuses:
    if "_" in key:
        statuses_result = (
            statuses_result
            + f'.cm-active .tag[href="#task/{key}"],\n'
            + f".cm-active .cm-tag-task{key},\n"
            + f".cm-active .cm-tag-task{key} + span.cm-hashtag,\n"
            + f".cm-active .cm-tag-task{key} + span.cm-hashtag + .cm-hashtag,\n"
        )
    else:
        statuses_result = (
            statuses_result
            + f'.cm-active .tag[href="#task/{key}"],\n'
            + f".cm-active .cm-tag-task{key},\n"
        )
statuses_result = statuses_result[:-2]
statuses_result += """ {
  font-size: var(--font-text-size);
}\n\n"""
for key, value in statuses.items():
    statuses_result = (
        statuses_result + f'.tag[href="#task/{key}"]:after,\n'
        f".cm-hashtag-begin.cm-tag-task{key}:after "
        + "{\n"
        + "  border-radius: 3px;\n"
        + "  background-color: var(--color-of-statuses);\n"
        + f'  content: "{value}";\n'
        + "}\n"
    )
print(statuses_result)
print(
    """
/* ░█▀▀░█▀█░▀█▀░█▀▀░█▀▀░█▀█░█▀▄░█░█ */
/* ░█░░░█▀█░░█░░█▀▀░█░█░█░█░█▀▄░░█░ */
/* ░▀▀▀░▀░▀░░▀░░▀▀▀░▀▀▀░▀▀▀░▀░▀░░▀░ */
"""
)
categories_result = ""
for key in categories:
    if "_" in key:
        categories_result = (
            categories_result
            + f'.tag[href="#category/{key}"],\n'
            + f".cm-tag-category{key},\n"
            + f".cm-tag-category{key} + span.cm-hashtag,\n"
            + f".cm-tag-category{key} + span.cm-hashtag + .cm-hashtag,\n"
        )
    else:
        categories_result = (
            categories_result
            + f'.tag[href="#category/{key}"],\n'
            + f".cm-tag-category{key},\n"
        )
categories_result = categories_result[:-2]
categories_result += """ {
  font-size: 0px;
  padding: 0;
}\n\n"""
for key in categories:
    if "_" in key:
        categories_result = (
            categories_result
            + f'.tag[href="#category/{key}"]:after,\n'
            + f".cm-tag-category{key}:after,\n"
            + f".cm-tag-category{key} + span.cm-hashtag:after,\n"
            + f".cm-tag-category{key} + span.cm-hashtag + .cm-hashtag:after,\n"
        )
    else:
        categories_result = (
            categories_result
            + f'.tag[href="#category/{key}"]:after,\n'
            + f".cm-tag-category{key}:after,\n"
        )
categories_result = categories_result[:-2]
categories_result += """ {
  font-size: var(--font-text-size);
}\n\n"""
for key in categories:
    if "_" in key:
        categories_result = (
            categories_result
            + f'.cm-active .tag[href="#category/{key}"],\n'
            + f".cm-active .cm-tag-category{key},\n"
            + f".cm-active .cm-tag-category{key} + span.cm-hashtag,\n"
            + f".cm-active .cm-tag-category{key} + span.cm-hashtag + .cm-hashtag,\n"
        )
    else:
        categories_result = (
            categories_result
            + f'.cm-active .tag[href="#category/{key}"],\n'
            + f".cm-active .cm-tag-category{key},\n"
        )
categories_result = categories_result[:-2]
categories_result += """ {
  font-size: var(--font-text-size);
}\n\n"""
for key, value in categories.items():
    categories_result = (
        categories_result + f'.tag[href="#category/{key}"]:after,\n'
        f".cm-hashtag-begin.cm-tag-category{key}:after "
        + "{\n"
        + "  border-radius: 3px;\n"
        + "  background-color: var(--color-of-categories);\n"
        + f'  content: "{value}";\n'
        + "}\n"
    )
print(categories_result)

Скрипт подразумевает такой запуск

python script.py > tags.css

Python-скрипт – это пока что самый большой костыль в данной системе.

Панель как в Todoist

наверх

Все приёмы и идеи, которые я вам показал, можно запихнуть в одну панель с bookmarks.

Вся система на одной панели. При этом сама панель напоминает панель в Todoist. Что как по мне плюс.

Эту же панель можно использовать на телефоне, но об этом чуть-позже.

Чтобы убрать лишние элементы с панели:

bookmarks.css
.workspace-leaf-content[data-type="bookmarks"] .tree-item-icon {
  display: none;
}

.workspace-leaf-content[data-type="bookmarks"] .tree-item-self {
  position: relative;
  left: -15px;
}

.view-action.mod-bookmark {
  display: none;
}

Обзор и взаимодействие с системой будет ровно таким же как и тут. Т.е. отличий с обычными таск-менджерами не будет.

Расширение логики и возможностей

наверх

Префиксы – приоритет, время, усилие

наверх

У нас уже есть префиксы с типом задачи и категорией. В принципе этого должно хватить, чтобы эффективно пользоваться системой. Однако если хочется, ну прям вообще как в таск-менджерах, то стоит добавить приоритет, времязатраты и требуемые усилия.

Приоритет

наверх

Мудрить я тут не буду и возьму метод ABCDE.

Символ

Тег

Оригинальный смысл

Альтернативный смысл

?

#priority/a

Критическая задача, которая должна быть сделана в обязательном порядке

Важная и срочная задача

?

#priority/b

Важная, но не критическая задача, которая должна быть сделана

Важная, но не срочная задача

?

#priority/c

Полезная/стандартная задача, которую стоит сделать (если её проигнорировать, то не будет значимых последствий)

Обычная, не срочная задача

?

#priority/d

Эту задачу стоит делегировать

Делегировать

?

#priority/e

Задача с очень низкой полезностью, которую на обзоре стоит пересмотреть или удалить

Пересмотреть или удалить

Альтернативный смысл я написал, чтобы сделать матрицу Эйзенхаура, основываясь на этих же приоритетах.

Зачем нам могут понадобиться приоритеты в персональной системе дел? Я думаю, что основных причин две:

  1. Чтобы они мозолили глаза и тем самым вынуждали нас делать сначала важное, а потом уже всё остальное

  2. Чтобы был вспомогательный способ рассортировать большой поток задач (основным способом является метка next_action)

Интегрировать приоритеты можно следующим образом.

Мы можем внутри групп, создать ещё одну группировку внутри статусов. Я покажу это на примере категории.

пример группировки на категории
not done 
tags include category/knowledge_base
group by function \
  if (task.tags.includes("#task/inbox"))         return "%%01%% ? Inbox"; \
  if (task.tags.includes("#task/next_action"))   return "%%02%% ? Next Action"; \
  if (task.tags.includes("#task/one-off"))       return "%%03%% 1️⃣ One-off"; \
  if (task.tags.includes("#task/multistep"))     return "%%04%% ? Multistep"; \
  if (task.tags.includes("#task/waiting_for"))   return "%%05%% ? Waiting for"; \
  if (task.tags.includes("#task/regular"))       return "%%06%% ? Regular"; \
  if (task.tags.includes("#task/someday"))       return "%%07%% ? Someday"; \
  if (task.tags.includes("#task/idea"))          return "%%08%% ? Idea"; \
  if (task.tags.includes("#task/reference"))     return "%%09%% ? Reference"; \
  return "%%00%% Without status";
group by function \
  if (task.tags.includes("#priority/a"))         return "%%01%% - ? Important and urgent"; \
  if (task.tags.includes("#priority/b"))         return "%%02%% - ? Important"; \
  if (task.tags.includes("#priority/c"))         return "%%03%% - ? Сommon task"; \
  if (task.tags.includes("#priority/d"))         return "%%04%% - ? Delegate"; \
  if (task.tags.includes("#priority/e"))         return "%%05%% - ? Eliminate"; \
  return "%%99%%";
hide task count
hide tags

Я понимаю, что запрос выглядит несколько перегружено. Но, а какие ещё есть варианты? Хотя, как бы с другой стороны, есть люди, которые пытаются в один запрос сразу запихнуть всё. Плохо ли это? Да не особо. Разве что такие запросы порой трудно "расшифровать".

Теперь сделаем матрицу Эйзенхауэра:

  • Верхний левый квадрант (do) – #priority/a

  • Верхний правый (schedule) - #priority/b и #priority/c

  • Нижний левый (delegate) - #priority/d и #task/waiting_for

  • Нижний правый (eliminate) - #priority/e

Матрицу я сделаю на Canvas.

Матрица Эйзенхауэра
Красота)
Красота)

Do

not done 
tags include priority/a
hide task count
hide tags

Schedule

not done 
(tags include priority/b) OR (tags include priority/c)
group by function \
  if (task.tags.includes("#priority/b"))         return "%%01%% - ? Important, non-urgent"; \
  if (task.tags.includes("#priority/c"))         return "%%02%% - ? Сommon task"; \
  return "%%99%%";
hide task count
hide tags

Delegate

not done 
(tags include priority/d) OR (tags include task/waiting_for)
group by function \
  if (task.tags.includes("#priority/d"))           return "%%01%% - ? Delegate"; \
  if (task.tags.includes("#task/waiting_for"))     return "%%02%% - ? Waiting"; \
  return "%%99%%";
hide task count
hide tags

Eliminate

not done 
tags include priority/e
hide task count
hide tags

Время выполнения

наверх

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

В Obsidian технически довольно трудно сделать так, чтобы можно было брать задачу и тут же превращать её в таймблок. Точнее трудно это сделать, когда задачи разнесены по разным периодическим заметкам. Так-то плагины для планирования времени в принципе есть.

Я отвлёкся.

Сбалансировать время можно и в системе без наворотов. Нужно лишь просто ввести какие-то ориентиры/правила, к которым стоит стремиться/выполнять.

За базовое утверждение примем мысль, что есть события внешние и внутренние.

Внешние события – это запланированные события или так называемый комитмент. К таким могут относиться, например, митинги и встречи с клиентами.

Внутренние события – это события, которые не начнутся, пока мы их не инициируем и не начнём делать. Например, мы не откроем Anki и не повторим 200 карточек, пока пинаем балду и чатимся в соц. сетях. Или мы не запулим новую фичу в наш личный проект, пока тратим своё свободное время на котиков в Youtube.

Внешние приходят из внешнего реального мира, внутренние исходят из нас самих.

Суть эффективного распределения времени заключатся в том, что когда у нас есть внешние события

такие как работа с клиентом, питч нового продукта и запланированная прогулка с женой
такие как работа с клиентом, питч нового продукта и запланированная прогулка с женой

нужно заполнить оптимально все свободные промежутки внутренними событиями

Внешние события мы берём из задач, которые имеют дату. Внутренние из всей остальной системы дел.

Для оценки времени будут использоваться следующие теги:

Символ

Тег

Смысл

Пример

?

#time/quick

Задача, которую можно сделать очень быстро (например, в пределах 15 минут)

ответить на email

?

#time/moderate

Задача, которая нуждается в небольшой вовлечённости (от 15 минут до нескольких часов)

подготовить презентацию по готовым результатам

?

#time/lengthy

Задача подразумевающая глубокую, сконцентрированную работу (от нескольких часов до 5)

провести детальное исследование по проекту

?

#time/long

Задача, которая требует значительных затрат времени и ресурсов (от 5 часов и более)

разработка стратегии

Я указал для всех меток примерное время. Это время является довольно условным – просто, чтобы можно было ориентироваться на что-то конкретное. Однако стоит заметить, что все эти оценки находится в пределах дня. Если задачи подразумевают очень долгое выполнение, то разумнее всё же переделать задачу в (проектную заметку/multistep) или использовать иные способы упорядочивания (например, диаграмму Ганта).

Отображение оценки времени я предлагаю использовать только на задачах с next_action. Обоснование в том, что эта метка отбирает наиболее актуальные задачи. Будет весьма удобно смотреть на предстоящие события, оценивать свободные части времени и заполнять их именно актуальными задачами.

пример для next_action
not done
tags include #task/next_action 
group by function task.tags.filter( (tag) => tag.includes("#category/") ).map( (tag) => tag.split('/')[1] ? tag.split('/').slice(1, 2) : '')
group by function \
  if (task.tags.includes("#time/quick"))         return "%%01%% - ? fast"; \
  if (task.tags.includes("#time/moderate"))      return "%%02%% - ? 1 pomodoro"; \
  if (task.tags.includes("#time/lengthy"))       return "%%03%% - ? long"; \
  if (task.tags.includes("#time/long"))          return "%%04%% - ? very long"; \
  return "%%99%%";
sort by function task.happens.format("YYYY-MM-DD")
hide task count
hide tags

Сложность или усилие

наверх

У оценки сложности похожая обоснованность, что и у оценки времени. За тем исключением, что теперь мы будем распределять не время, а оставшиеся силы.

Ментальную энергию довольно трудно измерить точно. Но зато в моменте ответить на вопрос "Я себя хорошо чувствую? Я бодрый?" можно весьма достоверно. На основе этой возможности и будет работать оценка сложности.

Символ

Тег

Смысл

#effort/easy

Задача простая – почти не требует ни физических, ни моральных сил

❤️‍?

#effort/medium

Задача требует заметных затрат ресурсов

?

#effort/hard

Очень трудозатратная или морально сложная задача

чтобы не было разночтения в символах
Отображение на Linux (Noto Color Emoji)
Отображение на Linux (Noto Color Emoji)

Логика тут довольная простая и она соответствует символам:

  • Easy task. Также просто как нарисовать сердечко | Нет никаких моральных отягощений

    • Если сил мало, то можно выбрать простенькие задачи, которые не требуют как таковой концентрации

  • Medium task. Нужно будет своё "сердечко" помучить

    • Если силы уже были потрачены на что-то значимое, но, мы например, отдохнули и в целом чувствуем себя неплохо, то можно выбрать средние задачи

    • Альтернативный смысл. Задача нервная или неприятная. На неё явно придется потратить заметное количество усилий

  • Hard task. Сложно на уровне – нарисуй мне достоверно человеческое сердце во всех деталях

    • Если мы полны сил, то можно замахнуться на сложную задачу

    • Альтернативный смысл. Задача, которую нам делать страшно или страшно неприятно. Задача нас может вытрепать или по итогу вообще истощить эго

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

Оценку сложности можно заюзать во всех статусах, кроме next_action. Идея в том, чтобы добирать из этих статусов задачи, на случай, если в next_action нет задач, которые бы соответствовали нашим текущим запасам сил.

пример для one-off
not done
tags include #task/one-off 
group by function task.tags.filter( (tag) => tag.includes("#category/") ).map( (tag) => tag.split('/')[1] ? tag.split('/').slice(1, 2) : '')
group by function \
  if (task.tags.includes("#effort/hard"))        return "%%01%% - ? hard"; \
  if (task.tags.includes("#effort/medium"))      return "%%02%% - ❤️‍? medium"; \
  if (task.tags.includes("#effort/easy"))        return "%%03%% - ❤ easy"; \
  return "%%99%%";
sort by function task.happens.format("YYYY-MM-DD")
hide task count
hide tags

Сводная таблица группировок

наверх

Группы – это первое группирование. Подгруппы – это как нужно сгруппировать внутри групп.

Тип

Группы

Подгруппы

? inbox

по упоминанию*

-

? next_action

#category/

#time/

1️⃣ one-off

#category/

#effort/

? multistep

#category/

#effort/

? waiting_for

#category/

#effort/

? regular

#category/

#effort/

? idea

#category/

#effort/

? reference

#category/

#effort/

? someday

#category/

#effort/

?️ category

#task/

#priority/

  • *это вот так group by backlink

Можете как-то поэкспериментировать с этой таблицей. Ну, или подумать о каких-то других способах, которые бы сделали систему ещё удобнее.

Стоит под конец отметить, что приоритет время и сложность – это вещи, которые делают классификацию задач уж слишком многомерной. Кому-то такое нравится и даже помогает в управлении делами. Кому-то наоборот нужен вообще один бинарный классификатор (сейчас/потом). Я нахожусь на стороне баланса – классификаторы должны быть, но не слишком много. Ровно также, например, я считаю, что тайм-блокинг может быть эффективен, но только вперемешку с обычными таск-листами.

Замена URL на markdown-ссылку

наверх

Эта функция уже есть в шаблоне для создания задачи, который я прикрепил в самом начале. Просто хотел отдельно сказать, что в нём есть также функция переделывающая URL на markdown-ссылки. Эта операция делается для экономии места.

demo

В качестве альтернативы вы можете конвертировать ссылки с помощью плагина Auto link title или с помощью этого шаблона сразу вставлять markdown-ссылку.

Комментарии

наверх

Мне видится два способа как можно делать комментарии к задачам.

  • 1-ый вариант – написать комментарий в самом тексте задачи

Чтобы отделить текст от комментария можно просто вставить какой-то разделитель.
Чтобы отделить текст от комментария можно просто вставить какой-то разделитель.

2-вариант – Явно указать, что у задачи есть комментарий и написать его под задачей

Я вам предлагаю использовать и тот, и тот способ.

Ссылки на других людей в тексте задачи

наверх

Без проблем можно добавлять ссылки на людей в задачи. А потом в заметках по этим же людям можно собирать задачи, где они упоминаются.

пример задач и заметки по человеку

Запросы на этот раз будут для dataviewjs.

Упоминания

dv.taskList(dv.pages().file.tasks
 .where(t => !t.completed)
 .where(t => !t.text.includes("#task/waiting_for"))
 .where(t => dv.func.contains(t.outlinks, dv.current().file.link)))

Делегировано

dv.taskList(dv.pages().file.tasks
 .where(t => !t.completed)
 .where(t => t.text.includes("#task/waiting_for"))
 .where(t => dv.func.contains(t.outlinks, dv.current().file.link)))

Смысл этих запросов в том, что они ищут задачи, где есть ссылка на текущую заметку.

Чтобы убрать обратные ссылки на периодические заметки в dataviewjs запросах, можно заюзать cssclass remove-dataview-title

remove-dataview-title.css
---
cssclasses:
  - remove-dataview-title
---
.remove-dataview-title :is(.block-language-dataview, .block-language-dataviewjs) h4 {
  display: none;
}

Чтобы пофиксить проблему с отступами у задач в теме Shimmering focus

tasks.css
/* https://github.com/chrisgrieser/shimmering-focus/issues/304#issuecomment-2107064048 */
:is(.block-language-dataview, .block-language-dataviewjs)
  ul.contains-task-list {
  --list-indent: 0.3em !important;
  padding-inline-start: 0 !important;
}
.contains-task-list .dataview.task-list-item-checkbox {
  margin-inline: 0 0.5em !important;
}

Поиск задач

наверх

Obsidian о нас позаботился, поэтому в нём есть операторы поиска задач. Нам нужно лишь добавить в bookmarks поисковые запросы с этими операторами. Раньше, кстати, приходилось возиться с регулярными выражениями.

Команда для добавления поискового запроса в избранное:

task:
task-todo:
task-done:

И ещё одна полезная вещь. Чтобы в поиске задачи рендерелись как в заметке, стоит добавить к себе плагин Query Control. Этот плагин ставится через BRAT.

Попытка в недельный календарь

наверх

Эта часть максимально экспериментальная.

Идея такая. Помимо того, что можно сделать календарь, который будет показывать задачи на текущей недели, можно ещё отобразить задачи, которые бы явно задавали расписание дня.

Допустим мы создаём периодическую заметку и явно прописываем в ней, чем мы будем заниматься в этот день.

пример периодической заметки

На этот день могут быть запланированы ещё какие-то события. Одно я прописал сразу в расписании, а другое мы увидим на недельном календаре.

weekly tasks
Красные/скрытые callout – это дни, которые уже прошли. Зелёный callout – это сегодня
Красные/скрытые callout – это дни, которые уже прошли. Зелёный callout – это сегодня

Чтобы показать сегодняшнюю дату (inline-запрос):

`$=dv.span(moment(Date.now()).format('MMMM DD, dddd (YYYY-MM-DD)'))`

Чтобы отобразить недельный календарь

`$=await dv.view("templates/views/week_tasks")`

Как видите, тут всё будет работать через dv.view.

templates/views/week_tasks/view.js
function query(day) {
  const query = `
due ${day}
path includes ${dv.current().file.folder}
hide task count
hide scheduled date
hide due date
hide done date
hide postpone button
`;
  return (query)
}
function query_shedule(date) {
  const query_shedule = `
dv.taskList(dv.pages('"' + dv.current().file.folder + '"')
.where(p => p.file.name == "${date}")
.file
.tasks
.where(t => !t.text.includes("#"))
)
`;
  return (query_shedule)
}
function callout(day, date) {
  const calloutTitle = day + " - [[periodic/daily/" + date + "|" + date + "]]" + `\n`
  const content = '#### On this day\n' + '```tasks\n' + query(day) + '\n```' +
    '\n#### Daily schedule\n' + '```dataviewjs\n' + query_shedule(date) + '\n```'
  let allText
  const today = moment().format("YYYY-MM-DD")
  if (date == today) {
    allText = `> [!calendar|today]+ ` + calloutTitle + content
  } else if (date > today) {
    allText = `> [!calendar]+ ` + calloutTitle + content
  } else {
    allText = `> [!calendar]- ` + calloutTitle + content
  }
  const lines = allText.split('\n');
  return lines.join('\n> ') + '\n'
}
function calendar() {
  const weekDayNumber = { Monday: 1, Tuesday: 2, Wednesday: 3, Thursday: 4, Friday: 5, Saturday: 6, Sunday: 7 }
  for (let day in weekDayNumber) {
    let date = moment().clone().startOf('isoWeek').add(weekDayNumber[day] - 1, 'days').format("YYYY-MM-DD")
    dv.paragraph(callout(day, date))
  }
}
calendar()

templates/views/week_tasks/view.css
/* calendar */
.callout[data-callout="calendar"] {
  --callout-color: 244, 65, 51;
  --callout-icon: lucide-calendar;
}

.callout[data-callout="calendar"][data-callout-metadata~="today"],
.callout[data-callout="calendar"][data-callout-metadata~="today"] {
  --callout-color: 0, 128, 0;
  --callout-icon: lucide-calendar;
}

.callout[data-callout="calendar"] .callout-content {
  padding: 0px;
  margin: 0px;
}
/* hide dataview title */
:is(.block-language-dataview, .block-language-dataviewjs) h4 {
  display: none;
}

Этот подход максимально экспериментальный. Это можно понять хотя бы из того, что недельный календарь содержит 14 запросов. Это явно неоптимальный способ. Был бы рад, если эту идею/подход кто-нибудь улучшил.

Плагин Datepicker

наверх

У плагина Tasks весьма убогий способ задания даты у задачи. Какое-то время, вместо него я юзал вот этот шаблон от anareaty. Однако сейчас появился плагин Datepicker, который решает проблему проставления даты тем способом, который мы и ожидаем – позволяет выбрать её на календаре.

Единственное, что для удобства команду вызова календаря стоит склеить с шаблоном ? . Это можно сделать с помощью QuickAdd.

Вложенный vault для телефона

наверх

У меня в Obsidian установлено многовато плагинов. Из-за них подгрузка на телефоне занимает целую вечность. Загружать всю базу знаний ради того, чтобы две задачки и одну мимолётную идею записать не фонтан.

В качестве решения можно сделать отдельный vault, в котором будет минимальное количество плагинов.

Если вы делали хранилище по моим гайдам, то у вас периодические заметки лежат в папке periodic. Я предлагаю создать в этой папке новый vault.

Для полноты картины можете посмотреть папки, которые есть в моей персональной системе.

Ну, а дальше нужно просто немного всё украсить.

Для начала нужно восстановить панель избранного

Далее стоит немного настроить панель инструментов

Тут самое главное добавить открытие command palette. И ещё обратите внимание, что создание периодической заметки я сделал по свайпу вниз (quick action). Это очень удобно, ибо подразумевает логику: открыл Obsidian, свайпнул вниз, написал нужные заметки.

В command palette для удобства стоит прикрепить шаблон создания задачи

Есть ещё одна полезная вещь.

Вероятно у вас тоже есть функция "замочка" на телефоне

Этот замочек делает так, чтобы Obsidian дольше удерживался в оперативной памяти. Это нужно, чтобы при повторном открытии Obsidian открывался мгновенно.

И на десерт. Открытие Obsidian можно ещё ускорить, если перейти на Olauncher.

Он делает взаимодействие с приложениями максимально минималистичным и быстрым.

В нём есть всего одна главная страница

Открытие Obsidian в таком лаунчере можно установить на свайп

Как видите Obsidian у меня открывается на свайп слева, а браузер на свайп справа.

Плагины, которые у меня установлены в "мобильном" vault:

  • Auto link title. Чтобы переделывать url в markdown-ссылки

  • Calendar. Календарь для навигации по периодическим заметкам

  • Dataview. Чтобы вся система работала

  • Datepicker. Для вставки даты

  • Emoji Shortcodes. Для вставки эмодзи

  • Force note view mode. Чтобы определённые заметки открывались только в режиме чтения

  • Link Favicons. Чтобы рядом с url была икона сайта

  • Note Toolbar. Для быстрой навигации

  • Periodic notes. Для организации периодических заметок

  • Query control. Чтобы в поиске рендерелись результаты

  • Tasks. Чтобы вся система работала

  • Templater. Для создания периодических заметок и чтобы шаблон для создания задач работал

Если так посмотреть на мобильное приложение Obsidian, то оно станет не таким уж и плохим, хах.

Несколько мелких уточнений:

  • Шаблон для создания задач и всё, что будет на панели избранного, нужно положить в такое место, чтобы они были доступны и на телефоне, и на компьютере (т.е. их нужно по итогу положить во вложенный vault)

  • Шаблон создания задачи работает нормально на Android. На IOS я его не проверял

  • Хранилище на телефоне с основным хранилищем у меня синхронизируется с помощью Syncthing

  • На телефоне всё равно писать и обозревать систему не очень удобно, поэтому ревью и всяческие дополнения/расширения/редактирование я делаю через компьютер

    • Т.е. телефон, в большинстве своём, мне нужен, чтобы быстро что-то записать и чтобы посмотреть предстоящие события и актуальные задачи

  • CSS для изменения отображения тегов придется продублировать в мобильный vault

  • Вы можете мобильный vault настроить и менять на компьютере

Лёгкое подытоживание и пример

наверх

Кажется, что система сложная. Но на деле это не так. Вся система, как мы помним, у нас находится на одной панели.

Чтобы задачи появились в этой системе, задачам нужно давать нужные теги. Все эти теги зашиты в шаблон для создания задачи, т.е. помнить их не нужно. При этом теги меняются через этот же один шаблон.

В начале статьи я показал общую структуру задачи. Теперь можно составить более конкретную схему:

Tasks сам соберёт задачи из периодических заметок, и сам их как надо сгруппирует.

Наша задача просто размышлять и в процессе формировать эти самые задачи.

пример формирования задач

Как видите, я все сделал в виде аутлайна. При этом я сразу добавил ссылки на те или иные техники, или концепции (именно в этом будет проявляться скрещивание системы дел и базы знаний).

Все задачи, которые мы напридумывали, будут агрегироваться в нужных местах. При этом, когда мы будем их делать, то так или иначе будем возвращаться в место, где их записали. И это плюс. Возвращаясь, мы будем видеть все действия, которые приняли, концепции и методы, которые использовали. Это почти как вести проект (проектную заметку), только в более свободной манере.

Ну, и да. Необязательно всё прям так масштабно делать. Можно и просто линейно записывать задачки друг за другом.

Преимущества и недостатки

наверх

Преимущества

наверх

  • Всё в Obsidian

    • Это плюс и как с точки зрения локального хранения – никто не нагнёт и не выпнет

    • И также плюс с точки зрения возможностей – с текстом, в рамках Obsidian, довольно много можно делать разных операций

  • Высокая степень автоматизации

    • Все задачи автоматом агрегируются в соответствии с их типом, категорией, приоритетами и т.д.

    • В том же Todoist автоматизацией можно разве что назвать сложные фильтрующие запросы – во всё остальном мы, либо сильно ограничены, либо нужно всё руками делать

  • Высокая скорость создания задач

  • Данную систему можно сделать поверх уже имеющейся

  • Теги можно массово переименовать, если вдруг подобрано какое-то неудачное слово

Недостатки

наверх

  • Есть костыли

  • Систему сначала нужно продумать и создать (всё строится на приёмах и хаках, а не по типу "шаблон скачал и всё завелось")

  • Система расширяемая, но при этом довольно много нужно делать манипуляций с кодом и запросами

  • С календарём всё сложно

    • Есть крайне интересное решение, которое может работать в связке с Tasks. Но оно подразумевает будто бы вообще вся система является системой дел. Ещё данное решение конфликтует с подходом в статье - префиксы делают отображение календаря жутко зашумленным

  • Делать массовые редактирования задач удобно, только, когда они находятся рядом. В остальных же случаях всё равно придется много кликать и тапать

  • Obsidian и его плагины работают не сказать бы, что быстро. На 2к активных задач запросы уже прям задумываются. На 5к скорее всего умрут мощный телефон и средний ПК. На 7к и более можно будет пойти потренироваться в зале, приготовить ужин и посмотреть кино, прежде tasks что-то покажет

    • Понятное дело, что запросы ищут по всей системе, во всех файлах. Плюс есть css-код. Да и вообще Obsidian не таск-менеджер. Но всё равно жалко, что такие банальные вещи плохо оптимизированы

    • Тот же Todoist работает всегда одинаково быстро

Итог

наверх

Рекомендовать такой подход всем, я однозначно не могу. В нём есть костыли и специфические особенности. Однако если вы гик и вам нравится копаться и организовывать подобные системы, то почему бы и нет?

Кстати говоря, сама по себе идея разбить задачу на префикс и контент, на мой взгляд, мощная. Просто реализовать красивым и при этом простым образом в Obsidian её довольно затруднительно.

P.S.

На это раз на статью меня вдохновили не кто-то другой или что-то другое, а наоборот отсутствие оных.

На этом у меня всё.


Задать вопрос или как-то расширить эту статью своим комментарием, вы также можете в telegram-канале. Если статья принесла вам пользу и вы в ответ хотите выразить свою благодарность в материальном виде, то можете сделать это вот тут или с помощью кнопки "Задонатить" (смотрите ниже).

Комментарии (10)


  1. mkpv
    04.08.2024 16:00
    +6

    Вспомнилось, что у меня тоже была система управления задачами на базе Обсидиан. Тоже с эмодзи и развесистыми тэгами. Плюс, я еще через Dataview кастомные вьюхи делал и через Charts графики строил, типа кармы. Хватило меньше чем на год. Ну то есть, когда ты такую систему строишь, продумываешь и в итоге реализуешь, то испытываешь большое воодушевление. Это примерно как pet проект работает.

    Но когда начинаешь всем этим реально пользоваться, то на дистанции в какие-то моменты у тебя становится очень мало энергии, которую высасывают другие задачи, и поддерживать всё это великолепие, где все разложено по полочкам и приятно щекочет перфекционизм, становится настолько влом, что мне лень было даже открывать Обсидиан. Может это только особенность такая, то для себя сделал вывод, что система должна быть максимально примитивной. На поддержку которой не тратишь примерно никакого времени. И чтобы приложение меньше чем за пару секунд открылось. И чтобы какой-бы бардак ты не навел, его можно было за 5 минут убрать.


    1. flowing_abyss Автор
      04.08.2024 16:00

      Классный комментарий.

      Хотя мне всё же есть к чему придраться)

      Плюс, я еще через Dataview кастомные вьюхи делал и через Charts графики строил, типа кармы.

      Система создаётся, чтобы решать какие-то проблемы. Возможно этими кастомными вьхами вы не решали никаких проблем. Поэтому они вам оказались по итогу не нужны.

      и поддерживать всё это великолепие

      Немного не понимаю. У вас каждый день формировались задачи в стиле?

      - [ ] поправить эту вьюху
      - [ ] убрать такую-то заметку с задачами
      - [ ] добавить новый dataview запрос
      - ...
      

      Или вы имеете в виду, что вам приходилось крутить педали, чтобы так ноут заряжать, дабы он вам все вьюхи отрисовал?

      Что в данном случае значит поддерживать?

      что система должна быть максимально примитивной

      В таком случае будет проще перейти на маленький бумажный блокнот.

      И чтобы приложение меньше чем за пару секунд открылось.

      Лучше блокнот.

      И чтобы какой-бы бардак ты не навел, его можно было за 5 минут убрать

      Бардак за 5 минут можно убрать, если в "комнате" по умолчанию всегда поддерживается чистота.

      В том же GTD эта чистота поддерживается, но всё равно не за счёт примитивности.

      Но вообще, в случае примитивной системы, её элементы перегрузятся за мгновение ока. Так что не знаю в чём преимущества у таких систем.


      1. mkpv
        04.08.2024 16:00
        +2

        Чтобы не вставлять имхо после каждого предложения, сразу напишу, что описываю исключительно персональный опыт. Он, судя по всему, существенно отличается от вашего. Это в порядке вещей.

        Система создаётся, чтобы решать какие-то проблемы. Возможно этими кастомными вьхами вы не решали никаких проблем. Поэтому они вам оказались по итогу не нужны.

        Я не использовал плагин Tasks. Я написал собственный урезанный вариант вариант на базе Dataview (Tasks основан на нём же, если что), без повторяющихся задач и прочего ненужного. Причину вы озвучили в посте. В Tasks нет группировки по типам задач. А у меня была - и по типам задач, и по проектам. В графиках можно было посмотреть статистику выполненных задач - ожидалось, что это придаёт мотивации, но нет. Плюс, progress bar для проектов - тоже мимо.

        В чём были недостатки старой системы из-за чего я от неё отказался:

        • Напряжно поддерживать тэги. При этом практически все они - не нужны.

        • Проще не иметь приоритета, потому что я и так знаю, что вот эта задача важная, а вот эта не очень. И если вдобавок приоритет устанавливается сверху, то завтра он может поменяться просто за одну минуту. Неважное станет важным и наоборот. В блокноте я просто перемещаю то что нужно вверх списка один хоткеем - всё. Контекст работы на день готов.

        • Проще не иметь категории, потому что я и так помню что к чему относится. Если нужна группировка, то я просто создаю отдельный файл или секцию.

        • Проще не ставить дедлайнов. Если я работаю на дядю, то уже нахожусь в контексте и знаю какую задачу надо закончить сегодня, какую до конца недели или месяца. Для этого есть багтрекеры, митинги и прочее. Если работаю на себя, то я не Илон Маск с миллионом задач на контроле, и тоже знаю с кём и о чём договорился. В целом даты вещь достаточно гибкая и намного более простой способ с ними работать это уделять определенное кол-во времени в неделю, а не медитировать каждый день на дедлайн в календаре.

        • Стремление ставить задачу на жёстко запланированную дату (которое пропагандируют примерно все тулзы) невероятно мешает. Оно по сути хорошо подходит разного рода менеджерам, у которых всегда чётко распланированный день, занятый митингами или созвонами. Для инженера это такое себе. Я могу напланировать кучу всего на день и потом бац, и несколько часов устранять последствия аварии, после чего у меня не останется энергии и я заработаю дебафф тем, что буду переносить таски на следующий день.

        • Если я в потоке, то мне вообще лень формулировать что-либо, потому что это отвлекает. Я могу запилить небольшой проект за день, с десятками задач не отвлекаясь вообще ни на что, и идти потом в TODO и описывать все это - просто лишняя трата времени.

        Если обобщить все сказанное, от TODO мне нужны свобода и минимальные хинты для выбора маршрута, а не надсмотрщик с плеткой и гиперконтроль. Текстовый документ, как вы заметили, для этого походит лучше, потому что энергия затрачиваемая на поддержку инструмента в конечном итоге подпитывает прокрастинацию.


        1. flowing_abyss Автор
          04.08.2024 16:00

          Мощно...

          Он, судя по всему, существенно отличается от вашего.

          Есть такое)

          Напряжно поддерживать тэги

          Если их ограниченное количество и если их проставление как-то автоматизировано, то не особо напряжно.

          Проще не иметь приоритета, потому что я и так знаю, что вот эта задача важная, а вот эта не очень.

          Это замкнутый круг. Вы смотрите на плоский список задач – оцениваете приоритетность. Открываете на следующий день этот же плоский список и снова оцениваете приоритетность. Такое оценивание видимо будет происходить до тех пор, пока задачи в вашем списке не закончатся. Т.е. вы вместо оптимизации, выбрали путь делания одной и той же не шибко полезной работы.

          Проще не иметь приоритета... И если вдобавок приоритет устанавливается сверху, то завтра он может поменяться просто за одну минуту. Неважное станет важным и наоборот. ... В блокноте я просто перемещаю то что нужно вверх списка один хоткеем - всё

          Как я вижу эту мысль:
          Приоритеты не нужны, но у меня есть список, где я приоритеты хоткеем задаю.

          Проще не иметь категории, потому что я и так помню что к чему относится.

          Пока человек работает, условно говоря, в рамках I-shaped компетенций, то ему не нужно как-то серьёзно делить свою жизнь на сферы. Однако как только ответственности становится больше, то человеку так или иначе приходится развивать какие-то другие навыки, изучать какие-то новые сферы (развиваться в T-shaped).

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

          К чему это я...

          У меня голова лопнет, если я буду держать отношения всего между всем.

          Если нужна группировка, то я просто создаю отдельный файл или секцию.

          Вы плодите новые сущности, вместо использования системы.

          Проще не ставить дедлайнов. ... Стремление ставить задачу на жёстко запланированную дату (которое пропагандируют примерно все тулзы) невероятно мешает.

          С этими мыслями я согласен. Поэтому в статье я не упарываюсь по идее таймблокинга или жёсткого задания дат для всех задач.

          и идти потом в TODO и описывать все это - просто лишняя трата времени

          С этим тоже согласен.

          ___

          Вообще я бы хотел отметить две вещи:

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

          2. Несмотря на ваши отличные замечания и мысли, они всё же не улучшают и не оптимизируют подходы в статье


          1. mkpv
            04.08.2024 16:00
            +1

            вы намеренно решили деградировать (примитизировали) свою систему дел, вместо того, чтобы её сделать лучше и оптимальнее

            Я бы предпочел использовать термин минимализм, но по сути верно. Я оптимизировал систему под то количество времени, которое на данный момент готов уделять на её поддержку.


    1. basilbasilbasil
      04.08.2024 16:00
      +1

      как опция - надиктовать таск чтобы нейросетка сама определила все проперти и занесла в лист