Раньше каждое утро я тонул в задачах и мыслях: что сделать прямо сейчас, кому ответить, какой приоритет у дел и о чём я вообще думал пару дней назад? Сейчас я открываю одну заметку — и сразу вижу все свои проекты, задачи, привычки и мысли. В этой статье я подробно, по шагам и максимально простым языком разберу всю свою систему ежедневных заметок — так, чтобы вы смогли собрать её у себя буквально за вечер.


Зачем вообще вести дневник в Obsidian

Бумажный блокнот — это прекрасно. Но у него есть один минус: то, что вы вчера записали, остаётся «вчера».

Задачи не переносятся сами, привычки не складываются в график, а мысли теряются между страницами.

В Obsidian всё иначе. Ежедневная заметка становится центром вашего дня:

🔁
Задачи
переносятся сами и приходят из проектов
📅
Календарь
синхронизация с Google Calendar
Привычки
кнопки и графики прогресса
💭
Мысли
свободное поле для идей и рассуждений

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

Эта простая система держит меня в концентрации: я делаю то, что действительно нужно, а не прокрастинирую. Давайте соберём её вместе.

Полное описание моей системы и структуры PARA — в предыдущих материалах на сайте.


Шаг 1. Что нужно установить

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

Сторонние плагины

Открываем Настройки → Сторонние плагины → Обзор и устанавливаем по очереди:

ПлагинЗачем нужен
DataviewСобирает данные из заметок (например, мысли по дням, графики)
Meta BindПревращает свойства заметки в кнопки и поля прямо в тексте
HomepageДелает домашнюю страницу, которая открывается при запуске
TemplaterЗапускает скрипты при создании заметки (перенос задач)
ButtonsСоздаёт кнопки, запускающие команды в один клик
QuickAdd«Мозг» кнопок: запускает макросы и скрипты

После установки Dataview зайдите в его настройки и включите все галочки (особенно Enable JavaScript Queries и Enable Inline JavaScript Queries) — без этого виджет календаря не заработает.

Включаем встроенные «Ежедневные заметки»

Obsidian умеет вести дневник прямо «из коробки». Заходим в Настройки → Основные плагины и включаем Ежедневные заметки. Затем настраиваем их под себя.

Три ключевые настройки:

  1. Формат названия заметки. У меня это просто день, месяц и год:

    DD-MM-YYYY
    

    Это важно: весь мой код (виджет, перенос задач) ищет заметки именно в формате ДД-ММ-ГГГГ. Если хотите добавить в название день недели — допишите буквы (например, dddd), но тогда поправьте формат и в коде. Какая буква за что отвечает, удобно смотреть на сайте format.cm (документация Moment.js).

  2. Папка новых заметок. У меня ежедневные заметки лежат в 2. Areas/Дневники/Ежедневные заметки. Я храню всё по структуре PARA, а ведение дневника — это «сфера жизни» (Area), поэтому ей место в папке Areas.

  1. Шаблон. Это структура, по которой будет создаваться каждая новая заметка. Мой шаблон лежит в 0. Files/4. Templates/Шаблон ежедневных заметок. «Templates» переводится как «шаблоны».

Вот так выглядит структура моей ежедневной заметки:

Свойства → виджет недели/календаря → планы на день → перенос задач → привычки → питание → мысли. Не всегда получается заполнить всё. Но само стремление делает меня дисциплинированнее.

Для тех, кто не хочет долго разбираться

Попробуйте мой готовый шаблон Obsidian и начните систематизировать информацию уже сегодня

Узнать про шаблон

Шаг 2. Свойства заметки (YAML)

Откроем шаблон и разберём его сверху вниз. Первое, что мы видим, — свойства заметки (их ещё называют YAML или frontmatter).

В чём их смысл? Свойства — это «официальные» данные заметки, которые легко считывают другие плагины. Например, график привычек берёт информацию именно из свойств, а не из обычного текста. Это правило стоит запомнить: что важно для графиков и автоматизации — храните в свойствах.

Свойства пишутся в самом верху заметки между двумя строчками из трёх дефисов:

---
Спорт: false
Чтение: false
Прогулка: false
Завтрак:
Перекусы:
Обед:
Ужин:
Итого_ккал:
---

Здесь две группы:

  • Привычки (Спорт, Чтение, Прогулка) — тип «флажок» (галочка). false значит «ещё не выполнено».
  • Питание (Завтрак, Обед, Ужин, Перекусы, Итого_ккал) — тип «текст», сюда записываем, что ели, и счётчик калорий.

Добавить своё свойство просто: в режиме свойств нажмите «+ Добавить свойство», впишите название и выберите тип (текст, число, флажок, дата). Через пару дней заполнения вы уже увидите динамику на графике.


Шаг 3. Синхронизация с Google Calendar и задачами

Сразу под свойствами в шаблоне идёт большой блок кода. Не пугайтесь — его написал ИИ, а я просто вставил. Этот код рисует красивый виджет: он показывает день недели, прогресс по неделе, а в режиме «Задачи» — синхронизируется с вашим Google Calendar и Google Tasks. Прямо из Obsidian вы видите события и задачи на день, можете отмечать их выполненными и добавлять новые.

Чтобы это заработало, одного кода в шаблоне мало. Нужно открыть Obsidian доступ к вашему Google-аккаунту. Делается это через бесплатный сервис Google Apps Script. Разберём по шагам — медленно и подробно.

3.1. Готовим сервер на scripts.google.com

1
Откройте script.google.com и нажмите «Новый проект».
2
Удалите весь текст в редакторе и вставьте код, который я привожу ниже.
3
Подключите сервис Google Tasks API: слева в меню «Службы» (значок «+») найдите Tasks API и нажмите «Добавить». Без этого шага код не увидит ваши задачи.

Шаг 3 пропускают чаще всего. Код использует Tasks.Tasklists.list(), а это «расширенная служба». Если не добавить Tasks API, скрипт будет падать с ошибкой.

Вот код, который нужно вставить в редактор (он отвечает за чтение событий/задач и за создание/закрытие задач):

// ======================================
// GOOGLE APPS SCRIPT — TASKS + CALENDAR
// ======================================
 
// Проверка авторизации (запусти один раз вручную)
function testAuth() {
  const taskLists = Tasks.Tasklists.list();
  Logger.log(taskLists);
  const events = CalendarApp.getDefaultCalendar().getEvents(new Date(), new Date());
  Logger.log(events.length + " событий сегодня");
}
 
// ====== ЧТЕНИЕ: события календаря + задачи на день ======
function doGet(e) {
  try {
    const tz = Session.getScriptTimeZone();
 
    // DEBUG-режим: открой GAS_URL?debug=1 в браузере — покажет ВСЕ задачи
    if (e && e.parameter && e.parameter.debug) {
      const debugLists = (Tasks.Tasklists.list().items) || [];
      const all = [];
      debugLists.forEach(list => {
        const items = (Tasks.Tasks.list(list.id, {
          showCompleted: true, showHidden: true, maxResults: 100
        }).items) || [];
        items.forEach(t => {
          all.push({ list: list.title, listId: list.id, title: t.title, due: t.due || null, status: t.status });
        });
      });
      return ContentService
        .createTextOutput(JSON.stringify({
          success: true, scriptTimeZone: tz,
          listsFound: debugLists.map(l => l.title),
          totalTasks: all.length, all: all
        }))
        .setMimeType(ContentService.MimeType.JSON);
    }
 
    const param = (e && e.parameter && e.parameter.date) ? e.parameter.date : null;
    const base = param
      ? new Date(+param.split("-")[0], +param.split("-")[1] - 1, +param.split("-")[2])
      : new Date();
 
    const start = new Date(base.getFullYear(), base.getMonth(), base.getDate(), 0, 0, 0);
    const end   = new Date(base.getFullYear(), base.getMonth(), base.getDate(), 23, 59, 59);
    const dayStr = Utilities.formatDate(base, tz, "yyyy-MM-dd");
 
    const events = CalendarApp.getDefaultCalendar().getEvents(start, end).map(ev => ({
      title: ev.getTitle(),
      allDay: ev.isAllDayEvent(),
      time: ev.isAllDayEvent() ? null : Utilities.formatDate(ev.getStartTime(), tz, "HH:mm")
    }));
 
    const tasks = [];
    const lists = (Tasks.Tasklists.list().items) || [];
    const today = new Date();
    const todayStr = Utilities.formatDate(today, tz, "yyyy-MM-dd");
    const isToday = dayStr === todayStr;
 
    lists.forEach(list => {
      const items = (Tasks.Tasks.list(list.id, { showCompleted: true, showHidden: true }).items) || [];
      items.forEach(t => {
        if (!t.due) return;
        const taskDay = t.due.substring(0, 10);
        const isExactDay = taskDay === dayStr;
        const isOverdue = isToday && taskDay < dayStr && t.status === "needsAction";
        if (isExactDay || isOverdue) {
          tasks.push({
            id: t.id, listId: list.id, title: t.title,
            status: t.status, completed: t.completed || null, overdue: isOverdue
          });
        }
      });
    });
 
    tasks.sort((a, b) => (a.overdue === b.overdue) ? 0 : (a.overdue ? -1 : 1));
 
    return ContentService
      .createTextOutput(JSON.stringify({ success: true, date: dayStr, events, tasks }))
      .setMimeType(ContentService.MimeType.JSON);
 
  } catch (error) {
    return ContentService
      .createTextOutput(JSON.stringify({ success: false, error: error.toString() }))
      .setMimeType(ContentService.MimeType.JSON);
  }
}
 
// ====== ЗАПИСЬ: создать ИЛИ закрыть задачу ======
function doPost(e) {
  try {
    const data = JSON.parse(e.postData.contents);
 
    if (data.action === "complete") {
      const listId = data.listId || Tasks.Tasklists.list().items[0].id;
      Tasks.Tasks.patch({ status: "completed" }, listId, data.taskId);
      return ContentService
        .createTextOutput(JSON.stringify({ success: true, message: 'Задача выполнена!' }))
        .setMimeType(ContentService.MimeType.JSON);
    }
 
    const title = data.title;
    const dueDate = data.dueDate;
    const taskLists = Tasks.Tasklists.list();
    const defaultTaskList = taskLists.items[0].id;
 
    const task = Tasks.Tasks.insert({ title: title, due: dueDate, status: 'needsAction' }, defaultTaskList);
 
    return ContentService
      .createTextOutput(JSON.stringify({ success: true, taskId: task.id, message: 'Задача добавлена!' }))
      .setMimeType(ContentService.MimeType.JSON);
 
  } catch (error) {
    return ContentService
      .createTextOutput(JSON.stringify({ success: false, error: error.toString() }))
      .setMimeType(ContentService.MimeType.JSON);
  }
}

3.2. Даём разрешение в первый раз

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

1
В выпадающем списке функций сверху выберите testAuth и нажмите «Выполнить» (▶).
2
Появится окно «Требуется авторизация» → нажмите «Проверить разрешения» и выберите свой Google-аккаунт.
3
Появится пугающий экран «Google не проверил это приложение». Это нормально — приложение ваше собственное. Нажмите внизу «Дополнительные настройки» → «Перейти на страницу … (небезопасно)».
4
Нажмите «Разрешить». Готово — доступ выдан. В журнале (Logs) вы увидите свои списки задач.

Экран «Google не проверил приложение» появляется у всех личных скриптов. Вы не передаёте данные никому постороннему — код работает только в вашем аккаунте.

3.3. Развёртывание и какую ссылку копировать

Теперь сделаем из кода настоящий веб-адрес, к которому будет обращаться Obsidian:

1
Справа вверху нажмите «Начать развёртывание» → «Новое развёртывание».
2
Нажмите на шестерёнку выбора типа и выберите «Веб-приложение» (Web app).
3
Заполните:
Запуск от имени: «Я» (ваш аккаунт)
У кого есть доступ: «Все» (Anyone)
4
Нажмите «Развернуть». Скопируйте «URL веб-приложения» — это та самая ссылка, которая заканчивается на /exec.

Копируйте именно ссылку, которая оканчивается на /exec. Ссылка с /dev работать в Obsidian не будет.

https://script.google.com/macros/s/AKfycbx…………/exec

3.4. Вставляем код виджета в шаблон

Теперь в шаблон ежедневной заметки вставляем код виджета. Это блок ```dataviewjs, который рисует карточку с неделей и календарём. Самое важное — в первой строке заменить ссылку в кавычках на вашу из шага 3.3:

const GAS_URL = "СЮДА_ВСТАВЬТЕ_СВОЮ_ССЫЛКУ_ЗАКАНЧИВАЮЩУЮСЯ_НА_exec";

Вот так это выглядит в начале кода виджета (заменяете только строку с GAS_URL, остальное не трогаете):

```dataviewjs
const GAS_URL = "https://script.google.com/macros/s/AKfyc…………/exec";

const obsidian = require("obsidian");

const fileName = dv.current().file.name;
const m = fileName.match(/^(\d{2})-(\d{2})-(\d{4})$/);

if (!m) {
  dv.paragraph("⚠️ Название заметки должно быть в формате ДД-ММ-ГГГГ");
} else {
  // … дальше идёт длинный код виджета: неделя, прогресс,
  //   кнопки «Задачи», загрузка событий и задач из календаря …
}
```

Готово! Теперь в заметке вы видите задачи на сегодня, просроченные задачи подсвечиваются красным, задачи можно отмечать выполненными и добавлять новые. Особенно удобно это на телефоне: открыл виджет — и быстро накидал дела.

Проверка работы. Откройте вашу ссылку в браузере, дописав в конце ?debug=1. Если увидите JSON со списком ваших задач — сервер работает правильно.

Для тех, кто не хочет долго разбираться

Попробуйте мой готовый шаблон Obsidian и начните систематизировать информацию уже сегодня

Узнать про шаблон

Шаг 4. Планы на день и кнопки

Следующий раздел шаблона — планы на день. Здесь у меня стоят ярлыки кнопок от плагина Buttons:

`button-spaced-repetition` `button-sport` `button-morning-routine` `button-work-on-project` `button-litso`

Каждый такой ярлык — это одна кнопка, которую я нажимаю в течение дня:

КнопкаЧто запускает
🃏 Интервальное повторениеВспомнить материал, который учу
💪 ТренировкиУпражнения на сегодня (меняются автоматически по группам мышц)
🙏 УтроМой утренний ритуал — медитация и концентрация
📋 ЗадачаОткрыть проекты и взять оттуда задачу (главная кнопка!)
😌 ЛицоЛичная рутина по уходу

Эти функции добавлялись постепенно. Сначала в заметке был только утренний ритуал. Потом я добавил интервальное повторение, тренировки и остальное — по мере необходимости, чтобы не перегружать мозг. Советую и вам начинать с одной-двух кнопок.


Шаг 5. Как устроены кнопки (Buttons) — простыми словами

Самое частое непонимание новичков: «почему в заметке написано `button-sport`, а появляется красивая кнопка?» Разберёмся.

Логика делится на две части: где кнопка описана и где она показана.

1. Заметка «MOC - Buttons»
Здесь лежат полные описания всех кнопок (код + ярлык ^button-…). Это «склад» кнопок.
2. Ежедневная заметка
Здесь стоит только короткий ярлык `button-sport` — и плагин подставляет кнопку со «склада».

Зачем так сложно? Чтобы не копировать длинный код кнопки в каждую заметку. Один раз описали — вставляем коротким ярлыком сколько угодно раз.

Как выглядит описание кнопки

Все мои кнопки хранятся в одной заметке MOC - Buttons (или просто «Кнопки»). Вот пример описания одной кнопки:

```button
name 💪 Тренировки
type command
action QuickAdd: Открыть тренировки
color black
class btn-inline
```
^button-sport

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

nameЧто написано на кнопке (можно с эмодзи).
type commandТип «команда» — кнопка запускает команду Obsidian.
actionКакую именно команду запустить (здесь — выбор из QuickAdd).
color / classВнешний вид. btn-inline — компактная кнопка в строку.
^button-sport⭐ Главное: ярлык (block id). Это «адрес» кнопки.

Что такое ^button-... и ярлык в тексте

Строчка ^button-sport сразу под блоком кода — это block id (якорь блока) в Obsidian. Она даёт кнопке уникальный адрес.

После этого в любой заметке достаточно написать ярлык в виде инлайн-кода (в одинарных обратных кавычках):

`button-sport`

Плагин Buttons видит этот ярлык, находит по адресу ^button-sport нужное описание и рисует на его месте рабочую кнопку. Можно ставить несколько ярлыков подряд в одну строку — получится ряд кнопок.

Правило простое:

^button-имя (с «домиком») — это где кнопка описана. `button-имя` (в кавычках) — это где кнопка показывается. Имя после button- должно совпадать.

Как создать свою кнопку с нуля

1
В заметке «MOC - Buttons» скопируйте любой готовый блок ```button … ```.
2
Поменяйте name (надпись) и action (какую команду запускать).
3
Снизу задайте уникальный ярлык, например ^button-water.
4
В нужной заметке напишите `button-water` — и кнопка появится.

Шаг 6. Главная кнопка «Задача»: связь дневника и проектов

Кнопка «📋 Задача» — одна из главных. Её ярлык — button-work-on-project, а запускает она через QuickAdd скрипт project-to-daily.

Сначала о том, откуда берутся задачи. Все мои проекты лежат в заметке MOC - Projects (папка 1. Projects по структуре PARA). Это канбан-доска на плагине Kanban: просто карточки задач, которые перетаскиваются из статуса в статус.

💡 Идеи
🔄 В работе
Готово

Кнопка «Задача» делает две умные вещи:

  1. Подтягивает задачи из проектов в дневник. Открывается окно с вашей канбан-доской, вы галочками отмечаете нужные карточки и нажимаете «Добавить» — они появляются в разделе «Мои планы на день».
  2. Двигает задачи по доске при выполнении. Когда вы отмечаете задачу выполненной (- [x]) прямо в дневнике, она автоматически переезжает в следующую колонку канбана (например, из «В работе» в «Готово») и убирается из заметки.

Есть и «турбо-режим»: если включить тумблер «🏁 В последнюю» (или дописать к задаче значок 🏁), при выполнении она поедет сразу в самую последнюю колонку доски.

Что в скрипте заменить под себя

Скрипт лежит у меня в 0. Files/4. Templates/Scripts/project-to-daily_01.js. Если будете брать его себе, в самом верху есть две строки, которые нужно настроить под свою систему:

const MOC_PATH = "1. Projects/MOC - Projects.md"; // ← путь к ВАШЕЙ канбан-доске
const LAST_COLUMN_MARKER = "🏁";                   // ← значок «сразу в последнюю колонку»
  • MOC_PATH — укажите путь к вашей главной канбан-доске с проектами (как она названа и в какой папке лежит).
  • LAST_COLUMN_MARKER — значок-метка для «турбо-режима». Можно оставить 🏁 или поставить любой свой.

Ещё один важный момент: скрипт ищет, куда вставлять задачи, по заголовку # Мои планы на день. Этот заголовок должен быть в вашей ежедневной заметке — иначе задачи добавятся в конец.

Для тех, кто не хочет долго разбираться

Попробуйте мой готовый шаблон Obsidian и начните систематизировать информацию уже сегодня

Узнать про шаблон

Шаг 7. Автоматический перенос невыполненных задач

В шаблоне, помимо кнопок, есть ещё один код — он переносит невыполненные задачи с прошлого дня на сегодня. Работает на плагине Templater: при создании новой заметки код срабатывает один раз и превращается в обычный список задач.

Логика простая и очень удобная:

📄 Вчерашняя заметка
находим последнюю заметку перед текущим днём
🔍 Ищем «- [ ]»
собираем все незакрытые задачи
📥 Сегодня
вставляем их в новую заметку

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

<%*
const moment = tp.obsidian.moment;
const fn = tp.file.title;
const date = moment(fn, 'DD-MM-YYYY');
 
// По воскресеньям добавляем кнопку резервной копии
if (date.isValid() && date.day() === 0) {
  tR += '- [ ] `button-local-backup`\n';
}
 
const pathToDailyNotes = "2. Areas/Дневники/Ежедневные заметки"; // ← ваш путь
const currentDate = moment(tp.file.title, 'DD-MM-YYYY');
const today = moment().startOf('day');
const referenceDate = currentDate.isAfter(today) ? today.clone().add(1, 'day') : currentDate;
 
function findLatestDailyNoteBeforeDate(beforeDate) {
  const folder = app.vault.getAbstractFileByPath(pathToDailyNotes);
  if (!folder || !folder.children) return null;
  const dailyFiles = folder.children
    .filter(file => {
      if (file.extension !== "md") return false;
      if (!file.name.match(/^\d{2}-\d{2}-\d{4}\.md$/)) return false;
      const fileDate = moment(file.name.replace('.md', ''), 'DD-MM-YYYY');
      return fileDate.isBefore(beforeDate) && fileDate.isSameOrBefore(today);
    })
    .sort((a, b) => {
      const dateA = moment(a.name.replace('.md', ''), 'DD-MM-YYYY');
      const dateB = moment(b.name.replace('.md', ''), 'DD-MM-YYYY');
      return dateB.valueOf() - dateA.valueOf();
    });
  return dailyFiles.length > 0 ? dailyFiles[0] : null;
}
 
if (!currentDate.isValid()) {
  tR += `❌ Не удалось определить дату из названия файла. Формат: DD-MM-YYYY.`;
} else {
  const yesterday = referenceDate.clone().subtract(1, 'day').format('DD-MM-YYYY');
  let targetFile = app.vault.getAbstractFileByPath(`${pathToDailyNotes}/${yesterday}.md`);
  let targetDate = yesterday;
  if (!targetFile) {
    targetFile = findLatestDailyNoteBeforeDate(referenceDate);
    if (targetFile) targetDate = targetFile.name.replace('.md', '');
  }
  if (!targetFile) {
    tR += `❌ Нет ежедневных заметок до ${referenceDate.format('DD-MM-YYYY')}.`;
  } else {
    const fileContent = await app.vault.read(targetFile);
    const tasks = fileContent.split("\n").filter(line => line.trim().startsWith("- [ ]"));
    if (tasks.length === 0) {
      tR += `✅ Нет невыполненных задач за ${targetDate}.`;
    } else {
      tR += `## 🔁 Невыполненные задачи из ${targetDate} (последняя заметка)\n\n`;
      tR += tasks.join("\n");
    }
  }
}
%>

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


Шаг 8. Кнопки привычек и питания (Meta Bind)

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

`INPUT[toggle:Спорт]` 🏃‍♂️ Спорт
`INPUT[toggle:Чтение]` 📖 Чтение
`INPUT[toggle:Прогулка]` 🚶‍♂️ Прогулка

Здесь INPUT[toggle:Спорт] — это переключатель, привязанный к свойству Спорт. Нажали тумблер в теле заметки — галочка автоматически встала в свойствах. А поскольку графики берут данные именно из свойств, ваша привычка тут же попадает в статистику.

Питание устроено так же, только через текстовые поля:

🥚 **Завтрак:** `INPUT[text:Завтрак]`
🍕 **Обед:** `INPUT[text:Обед]`
🥧 **Ужин:** `INPUT[text:Ужин]`
🥨 **Перекус:** `INPUT[text:Перекусы]`
 **Итого:** `INPUT[text:Итого_ккал]`

`button-calories`

В конце стоит кнопка button-calories«🌮 Посчитать калории». Это моя личная кнопка, которая с помощью ИИ прикидывает калорийность по тому, что я вписал в поля питания.

Идеально каждый день заполнять не получается — и это нормально. Но даже пара заполненных дней в неделю дают наглядную динамику на графиках привычек и калорий.


Шаг 9. Мысли — самый важный раздел

И самое главное — в самом низу шаблона раздел «Мысли». Здесь нет ни кода, ни шаблона. Это абсолютно пустое пространство для рассуждений.

Сюда я в течение дня записываю:

  • задачи на будущее и идеи;
  • проблемы, которые меня беспокоят;
  • размышления и наблюдения.

Если я не могу решить задачу прямо сейчас, я не давлю на себя. Я пишу в «Мыслях», почему не могу за неё взяться. Часто оказывается, что мозг зациклен на другой, внешней задаче — и осознание этого само снимает ступор.

Эти мысли работают на меня и дальше:

  1. На домашней странице. Завтра я увижу вчерашние мысли в специальном блоке на главной (Homepage).
  2. В заметке MOC - Дневники. Там стоит код, который собирает мысли со всех ежедневных заметок и показывает их по месяцам — день за днём. Из них рождаются новые задачи и атомарные заметки.
  3. С телефона. У меня настроен виджет, который пишет мысль сразу в нужный раздел сегодняшней заметки. Незаменимо, когда идея пришла на улице.

Код: все мысли из всех ежедневников по месяцам

Этот блок я вставляю в отдельную заметку MOC - Дневники (она лежит у меня в 2. Areas/Дневники). Он проходит по всем ежедневным заметкам месяца, вытаскивает из каждой раздел «Мысли» (а также свойства Мысль_дня и Инсайт_дня, если они есть) и выводит их списком. Кнопки «← Предыдущий / Следующий →» листают месяцы, а «🔽 Новые сначала» меняет сортировку.

Что заменить под себя

В коде есть одна строка с путём к папке ежедневных заметок — поставьте свой путь:

dv.pages('"2. Areas/Дневники/Ежедневные заметки"')

Также блок ищет заголовок ## Мысли и свойство Дата в заметках. Если у вас раздел называется иначе (например, # Мысли) — он всё равно сработает (ищет от 1 до 3 решёток). Свойство Дата должно быть в свойствах ежедневной заметки в формате даты.

Скопируйте блок целиком — от строки со словом dataviewjs и до закрывающих обратных кавычек:

```dataviewjs
let currentDate = new Date();
let sortOrder = "desc";

const container = dv.el("div", "");

// Панель управления
const controls = dv.el("div", "");
controls.style.cssText = `display: flex; align-items: center; gap: 8px; margin: 12px 0 20px 0; flex-wrap: wrap;`;

// Стиль для кнопок
function styleBtn(btn) {
  Object.assign(btn.style, {
    display: "inline-flex", "align-items": "center", "justify-content": "center",
    gap: "6px", padding: "8px 16px", "border-radius": "8px",
    border: "1px solid var(--background-modifier-border)",
    background: "var(--background-secondary)", color: "var(--text-normal)",
    cursor: "pointer", "font-size": "13px", "font-family": "inherit", "line-height": "1",
    transition: "background 0.15s, transform 0.1s, box-shadow 0.15s"
  });
  btn.onmouseenter = () => { btn.style.background = "var(--background-modifier-hover)"; btn.style.transform = "translateY(-1px)"; };
  btn.onmouseleave = () => { btn.style.background = "var(--background-secondary)"; btn.style.transform = "translateY(0)"; };
}

const spacer = dv.el("div", "");
spacer.style.cssText = "flex: 1;";

const prevBtn = dv.el("button", "⬅️ Предыдущий");
const nextBtn = dv.el("button", "Следующий ➡️");
const sortBtn = dv.el("button", "🔽 Новые сначала");
styleBtn(prevBtn); styleBtn(nextBtn); styleBtn(sortBtn);

controls.appendChild(prevBtn);
controls.appendChild(nextBtn);
controls.appendChild(spacer);
controls.appendChild(sortBtn);
container.appendChild(controls);

const contentDiv = dv.el("div", "");
container.appendChild(contentDiv);

async function renderMonth(date) {
  contentDiv.innerHTML = "";
  const start = new Date(date.getFullYear(), date.getMonth(), 1);
  const end = new Date(date.getFullYear(), date.getMonth() + 1, 0);

  const title = dv.el("h2", `${start.toLocaleDateString("ru", { month: "long", year: "numeric" })}`);
  title.style.cssText = "margin: 0 0 12px 0; font-size: 1.1em;";
  contentDiv.appendChild(title);

  // ↓↓↓ ЗАМЕНИТЕ путь на свою папку ежедневных заметок ↓↓↓
  const dailyNotes = dv.pages('"2. Areas/Дневники/Ежедневные заметки"')
    .where(p => {
      if (!p.Дата) return false;
      const d = new Date(p.Дата);
      return d >= start && d <= end;
    })
    .sort(p => p.Дата, sortOrder);

  for (const note of dailyNotes) {
    const content = await dv.io.load(note.file.path);
    const match = content.match(/#{1,3}\s*Мысли\s*\n([\s\S]*?)(?=\n#{1,3}\s|$)/i);
    const мысльДня = note["Мысль_дня"];
    const инсайтДня = note["Инсайт_дня"];

    if (!match && !мысльДня && !инсайтДня) continue;

    const block = dv.el("div", "");
    block.style.cssText = "border-bottom: 1px solid var(--background-modifier-border); padding: 8px 0;";

    block.appendChild(dv.el("h4", note.file.name));
    if (мысльДня) block.appendChild(dv.el("p", `💭 Мысль дня: ${мысльДня}`));
    if (инсайтДня) block.appendChild(dv.el("p", `💡 Инсайт: ${инсайтДня}`));
    if (match) block.appendChild(dv.el("p", `📝 Мысли:\n${match[1].trim()}`));

    contentDiv.appendChild(block);
  }
}

prevBtn.onclick = () => { currentDate.setMonth(currentDate.getMonth() - 1); renderMonth(currentDate); };
nextBtn.onclick = () => { currentDate.setMonth(currentDate.getMonth() + 1); renderMonth(currentDate); };
sortBtn.onclick = () => {
  if (sortOrder === "desc") { sortOrder = "asc"; sortBtn.textContent = "🔼 Старые сначала"; }
  else { sortOrder = "desc"; sortBtn.textContent = "🔽 Новые сначала"; }
  renderMonth(currentDate);
};

await renderMonth(currentDate);
```
📷 Скриншот: заметка MOC - Дневники со списком мыслей по месяцам и кнопками-переключателями
(вставьте сюда изображение)

Домашняя страница: привычки и мысли

Каждое утро Obsidian открывается у меня не на пустом месте, а на домашней странице (заметка MOC - HOME, плагин Homepage). На ней я сразу вижу две самые важные вещи: график привычек за текущий месяц и вчерашние мысли. Так день начинается с короткого «обзора себя».

Этот блок состоит из двух вкладок — «Привычки» и «Мысли». Вкладка «Привычки» строит график выполнения за месяц (данные берёт из свойств ежедневных заметок). Вкладка «Мысли» показывает раздел «Мысли» из вчерашней заметки.

Что заменить под себя

В начале кода одна строка с путём к папке ежедневных заметок — укажите свой путь:

const HABITS_FOLDER = "2. Areas/Дневники/Ежедневные заметки";

А в массиве habits перечислите свои привычки — названия должны точно совпадать с названиями свойств в шаблоне (Спорт, Чтение, Прогулка и т. д.).

Для графика привычек нужен плагин Obsidian Charts (он даёт функцию window.renderChart). Установите его так же, как остальные: Обзор → «Charts» → Установить и включить.

Скопируйте блок целиком — от строки со словом dataviewjs и до закрывающих обратных кавычек:

```dataviewjs
// ⚙️ НАСТРОЙКИ — замените пути и список привычек под себя
const { MarkdownRenderer } = require('obsidian');
const HABITS_FOLDER = "2. Areas/Дневники/Ежедневные заметки"; // ← ваша папка ежедневных заметок
const habits = [
  { name: "Спорт",    key: "Спорт" },
  { name: "Чтение",   key: "Чтение" },
  { name: "Прогулка", key: "Прогулка" }
];

// 📅 Текущий месяц
const now       = new Date();
const year      = now.getFullYear();
const month     = now.getMonth() + 1;
const pad       = n => String(n).padStart(2, "0");
const monthStr  = pad(month);
const totalDays = new Date(year, month, 0).getDate();
const MONTH_NAMES = ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"];
const monthName = MONTH_NAMES[month - 1];

// 📅 Вчерашняя дата (для раздела «Мысли»)
const yesterday = new Date(now);
yesterday.setDate(yesterday.getDate() - 1);
const yFileName = `${pad(yesterday.getDate())}-${pad(yesterday.getMonth() + 1)}-${yesterday.getFullYear()}`;
const yFilePath = `${HABITS_FOLDER}/${yFileName}.md`;

// 🛠️ Хелперы
const asBool = v => v === true || v === "true" || v === 1;
function gradientColor(pct) {
  let r, g, b = 0;
  if (pct < 50) { r = 255; g = Math.round(255 * pct / 50); }
  else          { g = 255; r = Math.round(255 - 255 * (pct - 50) / 50); }
  return `rgb(${r},${g},${b})`;
}

// 🚀 Рендер
let viewMode = "habits";

async function render() {
  this.container.innerHTML = "";

  const tabs = this.container.createEl("div");
  tabs.style.cssText = "display:flex; gap:8px; margin-bottom:14px; flex-wrap:wrap;";
  const makeTab = (label, mode) => {
    const active = viewMode === mode;
    const btn = tabs.createEl("button", { text: label });
    btn.style.cssText = "padding:6px 16px; border-radius:6px; cursor:pointer; border:1px solid var(--interactive-accent); " +
      (active ? "background:var(--interactive-accent); color:var(--text-on-accent); font-weight:600;"
              : "background:transparent; color:var(--text-normal);");
    btn.addEventListener("click", () => { if (viewMode !== mode) { viewMode = mode; render.call(this); } });
  };
  makeTab("Привычки", "habits");
  makeTab("Мысли",    "thoughts");

  const box = this.container.createEl("div");

  // ── Привычки ──────────────────────────────────────────────
  if (viewMode === "habits") {
    let pages = dv.pages(`"${HABITS_FOLDER}"`).where(p => {
      if (p.date) { const d = dv.date(p.date); return d && d.year === year && d.month === month; }
      const n = p.file.name;
      return n.includes(`-${monthStr}-${year}`) || n.includes(`${year}-${monthStr}-`);
    });
    if (pages.length === 0) { box.createEl("p", { text: `Нет данных за ${monthStr}.${year}.` }); return; }

    const counts   = habits.map(h => pages.filter(p => asBool(p[h.key])).length);
    const percents = counts.map(c => Math.round((c / totalDays) * 100));
    window.renderChart({
      type: "bar",
      data: {
        labels: habits.map(h => h.name),
        datasets: [{
          label: `Выполнение за ${monthStr}.${year} (из ${totalDays} дней)`,
          data: percents,
          backgroundColor: percents.map(p => gradientColor(p)),
          borderRadius: 4,
        }]
      },
      options: {
        indexAxis: "y",
        scales: {
          x: { min: 0, max: 100, ticks: { callback: v => v + "%" }, title: { display: true, text: "Процент" } },
          y: { title: { display: true, text: "Привычки" } }
        },
        plugins: {
          legend: { display: false },
          tooltip: { callbacks: { label: ctx => `${ctx.raw}% (${counts[ctx.dataIndex]} из ${totalDays} дней)` } },
          title: { display: true, text: `Привычки — ${monthName} ${year}` }
        }
      }
    }, box);

  // ── Мысли (со вчерашней заметки) ─────────────────────────
  } else if (viewMode === "thoughts") {
    const tfile = app.vault.getAbstractFileByPath(yFilePath);
    box.createEl("div", { attr: { style: "font-weight:600; margin-bottom:10px; color:var(--text-muted);" } })
       .setText(`Мысли — вчера (${yFileName})`);
    if (!tfile) { box.createEl("p", { text: `Заметка не найдена: ${yFileName}`, attr: { style: "color:var(--text-muted);" } }); return; }

    const content = await app.vault.read(tfile);
    const match = content.match(/^#{1,6}\s*Мысли\s*$/m);
    if (!match) {
      box.createEl("p", { text: "Раздел «Мысли» не найден в заметке.", attr: { style: "color:var(--text-muted);" } });
    } else {
      const startIdx    = content.indexOf(match[0]) + match[0].length;
      const afterText   = content.slice(startIdx);
      const nextHeading = afterText.match(/\n#{1,6}\s/);
      const thoughtsRaw = nextHeading ? afterText.slice(0, nextHeading.index).trim() : afterText.trim();
      if (thoughtsRaw) {
        const card = box.createEl("div", { attr: { style: "background:var(--background-secondary); border-left:3px solid var(--interactive-accent); border-radius:6px; padding:12px 14px; line-height:1.75; max-height:320px; overflow-y:auto;" } });
        await MarkdownRenderer.render(app, thoughtsRaw, card, yFilePath, this.component);
      } else {
        box.createEl("p", { text: "Раздел «Мысли» пуст.", attr: { style: "color:var(--text-muted);" } });
      }
    }
    const linkWrap = box.createEl("div", { attr: { style: "margin-top:10px;" } });
    linkWrap.createEl("a", {
      text: `Открыть ${yFileName} — Мысли`, cls: "internal-link",
      attr: { href: `${yFileName}#Мысли`, "data-href": `${yFileName}#Мысли`, style: "font-size:0.85em; color:var(--interactive-accent); text-decoration:none;" }
    });
  }
}
render.call(this);
```
📷 Скриншот: домашняя страница с вкладками «Привычки» и «Мысли»
(вставьте сюда изображение)

Для тех, кто не хочет долго разбираться

Попробуйте мой готовый шаблон Obsidian и начните систематизировать информацию уже сегодня

Узнать про шаблон

Бумажные дневники тоже в системе

Я не отказался от бумаги полностью — иногда приятно писать от руки. В моей системе для этого есть кнопка «📸 Фото в текст» (ярлык button-image-2-text, скрипт image-to-text).

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

📓 Бумажный лист
📸 Фото в текст (ИИ)
📝 Текст в заметке

А ещё я люблю рисовать схемы от руки — и любой такой рисунок легко вставляется прямо в заметку (через плагин Excalidraw или ту же кнопку рисунка). Так что ведение дневника в Obsidian не ограничено по функционалу: бумага, рисунки, голос, фото — всё стекается в одно место.


Итог

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

1.Плагины: Dataview, Meta Bind, Homepage, Templater, Buttons, QuickAdd.
2.Встроенные «Ежедневные заметки» + шаблон в папке Areas (PARA).
3.Свойства (YAML) для привычек и питания.
4.Виджет Google Calendar через scripts.google.com.
5.Кнопки и скрипт связи дневника с проектами.
6.Автоперенос задач, привычки, питание и раздел мыслей.

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

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

Для тех, кто не хочет долго разбираться

Попробуйте мой готовый шаблон Obsidian и начните систематизировать информацию уже сегодня

Узнать про шаблон

© 2026 Elton Labs. Все права защищены.