mirror of
https://github.com/kvasonaft/fb2-reader.git
synced 2026-07-22 08:31:14 +00:00
commit
67da77974d
5 changed files with 829 additions and 232 deletions
359
GUIDE.md
Normal file
359
GUIDE.md
Normal file
|
|
@ -0,0 +1,359 @@
|
|||
# FB2 Reader: подробное руководство по устройству плагина
|
||||
|
||||
Это руководство написано для человека, который **не знает JavaScript и TypeScript**, но хочет понять, как работает этот плагин — вплоть до каждой строчки. Читать лучше по порядку: сначала общая картина, потом основы языка, потом разбор кода.
|
||||
|
||||
## Содержание
|
||||
|
||||
1. [Что делает плагин](#1-что-делает-плагин)
|
||||
2. [Общая картина: как код становится плагином](#2-общая-картина-как-код-становится-плагином)
|
||||
3. [Файлы репозитория: кто за что отвечает](#3-файлы-репозитория-кто-за-что-отвечает)
|
||||
4. [Минимум JavaScript и TypeScript для чтения кода](#4-минимум-javascript-и-typescript-для-чтения-кода)
|
||||
5. [Как Obsidian запускает плагин](#5-как-obsidian-запускает-плагин)
|
||||
6. [Разбор main.ts: путь книги от файла до экрана](#6-разбор-maints-путь-книги-от-файла-до-экрана)
|
||||
7. [styles.css: как оформляется книга](#7-stylescss-как-оформляется-книга)
|
||||
8. [Как собрать, установить и менять плагин](#8-как-собрать-установить-и-менять-плагин)
|
||||
9. [Что нужно для публикации в каталоге Obsidian](#9-что-нужно-для-публикации-в-каталоге-obsidian)
|
||||
|
||||
---
|
||||
|
||||
## 1. Что делает плагин
|
||||
|
||||
FB2 Reader учит Obsidian открывать книги в формате FictionBook (файлы `.fb2` и `.fb2` внутри `.zip`). Возможности:
|
||||
|
||||
- **Читалка.** Файл `.fb2` открывается как красиво оформленная книга: обложка, название, авторы, аннотация, главы, стихи, цитаты, сноски, картинки, таблицы.
|
||||
- **Оглавление.** В правой боковой панели появляется список глав; клик по главе прокручивает книгу к ней.
|
||||
- **Запоминание позиции.** Плагин помнит, на каком абзаце вы остановились в каждой книге (до 300 книг), и при повторном открытии возвращает вас туда.
|
||||
- **Настройки вида.** Тема (светлая/тёмная/сепия), шрифт, размер шрифта, межстрочный интервал, цвет текста.
|
||||
|
||||
## 2. Общая картина: как код становится плагином
|
||||
|
||||
Цепочка выглядит так:
|
||||
|
||||
```
|
||||
src/main.ts ──(сборщик esbuild)──► main.js ──(читает Obsidian)──► работающий плагин
|
||||
▲ ▲
|
||||
исходник, который файл, который реально
|
||||
пишет человек исполняется
|
||||
```
|
||||
|
||||
Зачем эта цепочка нужна:
|
||||
|
||||
- **JavaScript (JS)** — язык, который умеют исполнять браузеры. Obsidian построен на технологии Electron (по сути, браузер Chrome в отдельном окне), поэтому плагины для него — это JavaScript.
|
||||
- **TypeScript (TS)** — это JavaScript плюс **типы**: возможность указать «эта переменная — число», «эта функция возвращает строку». Obsidian не понимает TypeScript, поэтому перед запуском типы «стираются», и остаётся чистый JavaScript. Зато на этапе написания кода компилятор TypeScript проверяет, что вы нигде не перепутали число со строкой и не обратились к несуществующему полю. Для новичка это огромная подмога: множество ошибок ловится до запуска.
|
||||
- **esbuild** — сборщик. Он делает две вещи: стирает типы из `src/main.ts` и «вклеивает» в результат код используемых библиотек (у нас это fflate для zip-архивов). На выходе — один самодостаточный файл `main.js`.
|
||||
- **Node.js и npm** — инструменты для запуска всего этого на вашем компьютере. Node.js исполняет JavaScript вне браузера (нужен сборщику), npm — менеджер пакетов: скачивает библиотеки, перечисленные в `package.json`, в папку `node_modules`.
|
||||
|
||||
Важное следствие: **`main.js` и `node_modules` не хранятся в git** — это «продукты производства», которые всегда можно получить заново командами `npm install` и `npm run build`. Именно поэтому их нет в этой ветке.
|
||||
|
||||
## 3. Файлы репозитория: кто за что отвечает
|
||||
|
||||
| Файл | Роль |
|
||||
|---|---|
|
||||
| `src/main.ts` | **Весь код плагина.** Единственный исходник. |
|
||||
| `styles.css` | Оформление: темы, отступы, шрифты, вид оглавления. |
|
||||
| `manifest.json` | «Паспорт» плагина для Obsidian: id, имя, версия, минимальная версия Obsidian. Без него Obsidian плагин не увидит. |
|
||||
| `package.json` | Описание проекта для npm: список зависимостей и команды сборки (`npm run build`, `npm run dev`). |
|
||||
| `package-lock.json` | Автогенерируемый файл: точные версии всех скачанных библиотек, чтобы сборка везде была одинаковой. Руками не редактируется. |
|
||||
| `tsconfig.json` | Настройки проверки типов TypeScript (насколько строго проверять, какой диалект JS считать целевым). |
|
||||
| `.gitignore` | Список того, что git не должен отслеживать: `node_modules/`, `main.js`. |
|
||||
| `GUIDE.md` | Этот документ. |
|
||||
|
||||
## 4. Минимум JavaScript и TypeScript для чтения кода
|
||||
|
||||
Этот раздел — «словарик», к которому можно возвращаться при чтении `main.ts`.
|
||||
|
||||
### Переменные и константы
|
||||
|
||||
```ts
|
||||
const name = "Война и мир"; // константа: перезаписать нельзя
|
||||
let count = 0; // переменная: можно менять
|
||||
count = count + 1;
|
||||
```
|
||||
|
||||
В коде плагина почти всё объявлено через `const` — это хороший стиль: сразу видно, что значение не поменяется.
|
||||
|
||||
### Типы (это уже TypeScript)
|
||||
|
||||
```ts
|
||||
const size: number = 17; // явно указан тип «число»
|
||||
const title: string = "FB2"; // «строка»
|
||||
const ready: boolean = true; // «да/нет»
|
||||
```
|
||||
|
||||
Часто тип не пишут — TypeScript сам его выводит: в `const size = 17` и так понятно, что это число. Тип указывают там, где вывести его неоткуда (параметры функций) или где хочется дополнительной страховки.
|
||||
|
||||
Ещё встречаются:
|
||||
|
||||
```ts
|
||||
string[] // массив строк: ["a", "b", "c"]
|
||||
Record<string, number> // объект-словарь: { "иван": 3, "мария": 5 }
|
||||
string | null // «строка ИЛИ null (пусто)»
|
||||
"light" | "dark" | "sepia" // только одна из этих трёх строк и ничего больше
|
||||
```
|
||||
|
||||
### Объекты и интерфейсы
|
||||
|
||||
Объект — набор именованных значений:
|
||||
|
||||
```ts
|
||||
const settings = { fontSize: 17, theme: "dark" };
|
||||
settings.fontSize // → 17 (доступ через точку)
|
||||
```
|
||||
|
||||
`interface` описывает, какой формы должен быть объект. Это чисто проверочная конструкция — в готовый `main.js` она не попадает:
|
||||
|
||||
```ts
|
||||
interface Fb2Settings {
|
||||
fontSize: number;
|
||||
theme: string;
|
||||
}
|
||||
```
|
||||
|
||||
Теперь, если где-то написать `settings.fontSze` (опечатка), TypeScript сразу подчеркнёт ошибку.
|
||||
|
||||
### Функции
|
||||
|
||||
Функция — именованный кусок кода, который принимает входные значения (параметры) и возвращает результат:
|
||||
|
||||
```ts
|
||||
function double(n: number): number { // принимает число, возвращает число
|
||||
return n * 2;
|
||||
}
|
||||
double(21) // → 42
|
||||
```
|
||||
|
||||
Есть и краткая запись — **стрелочная функция**. Она часто передаётся другой функции как «что делать с каждым элементом»:
|
||||
|
||||
```ts
|
||||
(n) => n * 2 // то же, что double, но без имени
|
||||
[1, 2, 3].map((n) => n * 2) // → [2, 4, 6]: применить к каждому элементу
|
||||
[1, 2, 3].filter((n) => n > 1) // → [2, 3]: оставить подходящие
|
||||
```
|
||||
|
||||
В `main.ts` стрелочные функции повсюду: «когда произойдёт клик — выполни вот это», «для каждого автора — склей имя и фамилию».
|
||||
|
||||
### Классы
|
||||
|
||||
Класс — чертёж объекта: его **поля** (данные) и **методы** (действия). По одному чертежу можно создать много объектов.
|
||||
|
||||
```ts
|
||||
class Book {
|
||||
title: string; // поле
|
||||
|
||||
constructor(title: string) { // вызывается при создании объекта
|
||||
this.title = title; // this — «этот самый объект»
|
||||
}
|
||||
|
||||
describe(): string { // метод
|
||||
return "Книга: " + this.title;
|
||||
}
|
||||
}
|
||||
|
||||
const b = new Book("Муму"); // создание объекта по чертежу
|
||||
b.describe() // → "Книга: Муму"
|
||||
```
|
||||
|
||||
Ключевое слово `extends` — **наследование**: «возьми готовый класс и дострой его».
|
||||
|
||||
```ts
|
||||
class AudioBook extends Book { ... }
|
||||
```
|
||||
|
||||
Весь плагин построен на наследовании: Obsidian даёт заготовки (`Plugin`, `FileView`, `ItemView`, `PluginSettingTab`), а мы наследуемся от них и заполняем нужные методы. `super` внутри метода означает «вызови эту же логику у родителя». Пометка `private` у поля значит «доступно только внутри класса» — снаружи трогать нельзя.
|
||||
|
||||
### async / await: ожидание медленных операций
|
||||
|
||||
Чтение файла с диска — «медленная» операция. Если бы код просто ждал её, окно Obsidian замирало бы. Поэтому такие операции возвращают **обещание** (`Promise`) — «результат будет позже». Слово `await` означает «дождись результата, но не замораживай программу», а функция, внутри которой есть `await`, помечается словом `async`:
|
||||
|
||||
```ts
|
||||
async function readBook(file: TFile) {
|
||||
const bytes = await this.app.vault.readBinary(file); // ждём чтения с диска
|
||||
// сюда придём, когда bytes уже получены
|
||||
}
|
||||
```
|
||||
|
||||
### Полезные мелкие операторы
|
||||
|
||||
```ts
|
||||
a ?? b // «a, а если a — null/undefined, то b»
|
||||
obj?.field // «возьми field, а если obj пустой — верни undefined без ошибки»
|
||||
a || b // «a, а если a пустое/ложное — b»
|
||||
condition ? x : y // «если condition — то x, иначе y»
|
||||
`размер: ${n}px` // шаблонная строка: подставляет значение n внутрь текста
|
||||
```
|
||||
|
||||
### DOM: как код «рисует» на экране
|
||||
|
||||
Страница в браузере — это дерево элементов (**DOM**): абзацы, заголовки, картинки вложены друг в друга. Код может создавать элементы, менять их и удалять — именно так плагин «рисует» книгу. Obsidian добавляет к стандартным средствам удобные сокращения:
|
||||
|
||||
```ts
|
||||
parent.createEl("p", { text: "Привет", cls: "fb2-p" })
|
||||
// создать внутри parent абзац <p class="fb2-p">Привет</p>
|
||||
|
||||
parent.createDiv({ cls: "fb2-book" }) // создать <div class="fb2-book">
|
||||
container.empty() // удалить всё содержимое
|
||||
el.addClass("fb2-reader") // добавить CSS-класс
|
||||
```
|
||||
|
||||
CSS-класс (`cls`) — это «ярлык», по которому файл `styles.css` находит элемент и оформляет его.
|
||||
|
||||
## 5. Как Obsidian запускает плагин
|
||||
|
||||
1. Obsidian сканирует папку `.obsidian/plugins/` в хранилище. В папке плагина он ожидает три файла: `manifest.json`, `main.js`, `styles.css`.
|
||||
2. Прочитав `manifest.json`, Obsidian узнаёт id и версию плагина.
|
||||
3. При включении плагина Obsidian загружает `main.js`, находит в нём класс, помеченный `export default` (у нас это `Fb2ReaderPlugin`), создаёт его и вызывает метод **`onload()`**.
|
||||
4. В `onload()` плагин «представляется»: регистрирует свои виды, расширения файлов, команды, вкладку настроек. Дальше Obsidian сам вызывает нужные методы в нужные моменты — это называется «инверсия управления»: не мы командуем программой, а программа зовёт нас.
|
||||
5. При выключении плагина вызывается **`onunload()`** — там нужно прибрать за собой.
|
||||
|
||||
Ключевые понятия Obsidian, встречающиеся в коде:
|
||||
|
||||
- **Vault (хранилище)** — папка с вашими заметками. `this.app.vault.readBinary(file)` — прочитать файл из хранилища.
|
||||
- **Workspace (рабочая область)** — расположение окон: вкладки, панели.
|
||||
- **Leaf (лист)** — одна «ячейка» рабочей области (вкладка или панель), в которую вставляется вид.
|
||||
- **View (вид)** — содержимое листа. Наша читалка и наше оглавление — это виды.
|
||||
|
||||
## 6. Разбор main.ts: путь книги от файла до экрана
|
||||
|
||||
Файл состоит из восьми разделов (они отмечены комментариями-линейками). Здесь — логика каждого; построчные пояснения смотрите в комментариях самого файла.
|
||||
|
||||
### 6.1. Импорты
|
||||
|
||||
Вверху файла подключаются инструменты из пакета `obsidian` (классы-заготовки и функция `debounce`) и функция `unzipSync` из библиотеки fflate. При сборке esbuild вклеивает код fflate внутрь `main.js`, а пакет `obsidian` не вклеивает (флаг `--external:obsidian` в команде сборки) — его предоставляет сам Obsidian во время работы.
|
||||
|
||||
### 6.2. Типы и настройки по умолчанию
|
||||
|
||||
Интерфейсы `TocItem`, `ReadingPosition`, `Fb2Settings`, `Fb2Data` описывают форму данных плагина. `DEFAULT_SETTINGS` — настройки при первом запуске. `TEXT_COLORS` — варианты для выпадающего списка «цвет текста».
|
||||
|
||||
### 6.3. Таблицы тегов — сердце «перевода» FB2 в HTML
|
||||
|
||||
FB2 — это XML-формат со своими тегами. Например, глава книги выглядит так:
|
||||
|
||||
```xml
|
||||
<section>
|
||||
<title><p>Глава первая</p></title>
|
||||
<p>Все счастливые семьи похожи друг на друга...</p>
|
||||
</section>
|
||||
```
|
||||
|
||||
Браузер таких тегов не знает, поэтому каждый надо превратить в HTML-аналог. Большинство превращений тривиальны, и они описаны тремя таблицами:
|
||||
|
||||
- `BLOCK_CONTAINERS`: `section`, `poem`, `cite`... → обёртка (`div` или `blockquote`) с CSS-классом; содержимое обрабатывается дальше.
|
||||
- `BLOCK_PARAGRAPHS`: `p`, `subtitle`, `v`, `text-author` → абзац `<p>` с CSS-классом.
|
||||
- `INLINE_TAGS`: `emphasis` → `<em>` (курсив), `strong` → `<strong>` (жирный) и т.п.
|
||||
|
||||
Хотите узнать, как отображается тег — ищите его в этих таблицах. Хотите поддержать новый тег — чаще всего достаточно добавить одну строку в таблицу и стиль в `styles.css`.
|
||||
|
||||
### 6.4. Вспомогательные функции
|
||||
|
||||
- `detectEncoding` / `decodeFb2` — превращают байты файла в текст. Старые FB2-книги часто в кодировке windows-1251, поэтому кодировку приходится угадывать: сначала по служебным байтам BOM, потом по объявлению `encoding="..."` в начале XML.
|
||||
- `extractFb2FromZip` — достаёт `.fb2` из zip-архива с помощью fflate.
|
||||
- `getSystemFonts` — запрашивает у системы список установленных шрифтов (для настроек). Результат кэшируется; если возможность недоступна — возвращается пустой список, и настройки покажут текстовое поле вместо выпадающего списка.
|
||||
- `getHref` — достаёт адрес ссылки, пробуя все варианты записи атрибута (`xlink:href`, `l:href`, `href`), которые встречаются в реальных книгах.
|
||||
- `copyId` — переносит `id` тега FB2 на HTML-элемент, чтобы работали внутренние ссылки (сноски).
|
||||
|
||||
### 6.5. Класс Fb2View — читалка
|
||||
|
||||
Наследуется от `FileView` (вид, привязанный к файлу). Когда пользователь открывает `.fb2`, Obsidian создаёт `Fb2View` и вызывает `onLoadFile`. Внутри — вся цепочка:
|
||||
|
||||
```
|
||||
байты файла → (unzip при необходимости) → текст → XML-дерево → HTML-элементы
|
||||
```
|
||||
|
||||
1. **`onLoadFile`** читает файл, распаковывает zip, декодирует текст и разбирает его встроенным `DOMParser` в дерево объектов. Если XML битый — показывает сообщение об ошибке.
|
||||
2. **`collectBinaries`** собирает картинки. В FB2 они лежат в тегах `<binary>` как текст base64; из них делается словарь «id → data-URL», и `<img>` показывает картинку прямо из этой строки, без внешних файлов.
|
||||
3. **`renderBook`** рисует титульную страницу (`renderTitleInfo`: обложка, название, авторы, аннотация), затем каждое `<body>` книги. Второе `<body name="notes">` — это сноски; они оформляются отдельно и не попадают в оглавление. В конце вешается один обработчик кликов на всю книгу: клик по внутренней ссылке находит элемент-цель по `data-fb2-id` и плавно прокручивает к нему.
|
||||
4. **`renderBlock`** — рекурсивный «переводчик» блочных тегов: сначала смотрит в таблицы (случаи 1 и 2), затем обрабатывает особые теги (`title`, `image`, `table`, `empty-line`), а незнакомые теги прозрачно «проходит насквозь», отрисовывая их содержимое. Рекурсия (метод вызывает сам себя для детей элемента) позволяет обойти дерево любой глубины. Параметр `depth` растёт при входе в каждую `<section>` — от него зависит уровень заголовка (`h2`, `h3`...). Попутно заголовки складываются в `tocItems` — этот список потом показывает панель оглавления.
|
||||
5. **`renderInline`** — то же для строчного содержимого: текст добавляется как есть, простые теги берутся из таблицы `INLINE_TAGS`, ссылки `<a>` обрабатываются отдельно (сноски оборачиваются в `<sup>` — маленькая цифра сверху).
|
||||
|
||||
**Позиция чтения.** Хранить позицию в пикселях ненадёжно: смените шрифт — и всё съедет. Поэтому хранится **номер первого видимого блока текста**. При прокрутке (не чаще раза в 800 мс — за это отвечает `debounce`) вычисляется, какой блок сейчас первый на экране, и его номер сохраняется. При открытии книги `restoreReadingPosition` прокручивает к блоку с сохранённым номером.
|
||||
|
||||
### 6.6. Класс Fb2TocView — панель оглавления
|
||||
|
||||
Простой вид: хранит ссылку на читалку (`source`) и рисует её `tocItems` — по строке на главу, с отступом по глубине вложенности. Клик по строке показывает вкладку книги и прокручивает к главе. Сама панель ничего не вычисляет — всю работу сделала читалка при отрисовке книги.
|
||||
|
||||
### 6.7. Класс Fb2ReaderPlugin — «дирижёр»
|
||||
|
||||
Тот самый класс с `export default`, который создаёт Obsidian. В `onload()`:
|
||||
|
||||
- загружает сохранённые данные (`loadData()` читает `data.json` в папке плагина) и накладывает их на настройки по умолчанию;
|
||||
- регистрирует оба вида и говорит, что расширения `fb2` и `zip` открываются в читалке (`registerExtensions`);
|
||||
- добавляет вкладку настроек, кнопку на боковой панели (открывает настройки) и команду «Open table of contents» для палитры команд;
|
||||
- подписывается на смену активной вкладки, чтобы панель оглавления всегда показывала содержание активной книги.
|
||||
|
||||
Также этот класс — хранитель данных: `getPosition`/`setPosition` для позиций чтения (с ограничением в 300 книг — `prunePositions`), `applySettings` для применения настроек. Сохранение на диск отложенное (`debounce`, раз в 2 секунды), чтобы не писать файл слишком часто.
|
||||
|
||||
Метод `applySettings` — важное место: он записывает значения настроек в **CSS-переменные** на элементе `<body>` (например, `--fb2-font-size: 17px`). Код не занимается оформлением сам — он лишь «публикует» значения, а `styles.css` их читает. Об этом — следующий раздел.
|
||||
|
||||
### 6.8. Класс Fb2SettingTab — вкладка настроек
|
||||
|
||||
Obsidian вызывает `display()` при каждом открытии настроек. Каждая настройка создаётся классом `Setting`: имя, описание, поле ввода. Общий приём: обработчик `onChange` записывает новое значение в `plugin.fb2Settings` и вызывает `plugin.saveSettings()` — настройка применяется немедленно, без кнопки «Сохранить».
|
||||
|
||||
Две хитрости:
|
||||
|
||||
- **Гонка отрисовок.** Список шрифтов загружается не мгновенно. Если пользователь успел закрыть и снова открыть настройки, запускается вторая отрисовка, и первая, «отставшая», могла бы перерисовать всё поверх новой. Счётчик `renderToken` решает это: каждая отрисовка получает номер, и если к моменту готовности номер уже не последний — она тихо выходит.
|
||||
- **Чужое значение в списке.** Если в настройках сохранён шрифт или цвет, которого нет в списке вариантов, он добавляется отдельным пунктом — иначе выпадающий список молча «слетел» бы на первый вариант.
|
||||
|
||||
## 7. styles.css: как оформляется книга
|
||||
|
||||
CSS — язык оформления: «у элементов с таким-то классом такой-то шрифт, отступ, цвет». Каждому созданному в коде элементу присвоен класс с префиксом `fb2-` (`fb2-p` — абзац, `fb2-title` — заголовок, `fb2-epigraph` — эпиграф...), и на каждый класс в `styles.css` есть правило.
|
||||
|
||||
Два механизма стоит понять:
|
||||
|
||||
**CSS-переменные** — мостик между настройками и оформлением:
|
||||
|
||||
```css
|
||||
.fb2-book {
|
||||
font-size: var(--fb2-font-size, 1.05em);
|
||||
}
|
||||
```
|
||||
|
||||
Читается так: «размер шрифта — значение переменной `--fb2-font-size`, а если она не задана — 1.05em». Код (`applySettings`) записывает переменную на `<body>`, стиль её подхватывает. Поменяли размер в настройках — книга мгновенно перерисовалась, без участия кода отрисовки.
|
||||
|
||||
**Классы тем.** Выбор темы добавляет на `<body>` класс `fb2-theme-dark` / `-light` / `-sepia`. В `styles.css` для каждого класса задан свой набор цветов:
|
||||
|
||||
```css
|
||||
body.fb2-theme-sepia .fb2-reader {
|
||||
background-color: #f4ecd8 !important;
|
||||
color: #5b4636;
|
||||
}
|
||||
```
|
||||
|
||||
Читается: «если на body есть класс fb2-theme-sepia, то внутри читалки — бумажный фон и коричневый текст». Заодно переопределяются стандартные переменные Obsidian (`--text-normal`, `--link-color`...), чтобы и вложенные элементы подхватили цвета темы.
|
||||
|
||||
## 8. Как собрать, установить и менять плагин
|
||||
|
||||
Один раз после клонирования репозитория:
|
||||
|
||||
```bash
|
||||
npm install # скачать зависимости в node_modules
|
||||
```
|
||||
|
||||
Собрать плагин:
|
||||
|
||||
```bash
|
||||
npm run build # проверка типов + сборка main.js
|
||||
```
|
||||
|
||||
Команда состоит из двух шагов (см. `package.json`): `tsc -noEmit` проверяет типы и ничего не создаёт; `esbuild` собирает `src/main.ts` в `main.js`.
|
||||
|
||||
Установить в Obsidian вручную: скопировать `main.js`, `manifest.json`, `styles.css` в папку `<хранилище>/.obsidian/plugins/fb2-reader/` и включить плагин в настройках Obsidian.
|
||||
|
||||
Для разработки удобнее режим наблюдения:
|
||||
|
||||
```bash
|
||||
npm run dev # пересобирает main.js при каждом сохранении main.ts
|
||||
```
|
||||
|
||||
После пересборки нужно перезагрузить плагин в Obsidian (выключить-включить в настройках или командой «Reload app without saving»).
|
||||
|
||||
Типичный цикл изменения: правите `src/main.ts` → сборка → копирование в хранилище → перезагрузка плагина → проверка на реальной книге.
|
||||
|
||||
## 9. Что нужно для публикации в каталоге Obsidian
|
||||
|
||||
Когда код станет полностью понятен, для публикации потребуется:
|
||||
|
||||
1. **README.md на английском** — описание плагина, скриншоты, инструкция.
|
||||
2. **LICENSE** — файл лицензии (в `package.json` уже указана MIT).
|
||||
3. **Согласовать версии**: сейчас в `manifest.json` версия 0.7.1, а в `package.json` — 0.1.0; при публикации версии релизов должны совпадать с `manifest.json`.
|
||||
4. **GitHub-релиз**: создать релиз с тегом, равным версии из `manifest.json`, и приложить к нему три файла: `main.js`, `manifest.json`, `styles.css` (именно поэтому `main.js` не хранится в репозитории — он прикладывается к релизу).
|
||||
5. **Заявка в каталог**: форк репозитория [obsidianmd/obsidian-releases](https://github.com/obsidianmd/obsidian-releases), добавление своего плагина в `community-plugins.json`, pull request и прохождение ревью команды Obsidian (они проверяют код на соответствие [гайдлайнам](https://docs.obsidian.md/Plugins/Releasing/Plugin+guidelines)).
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2026 kvasonaft
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
import esbuild from "esbuild";
|
||||
import process from "process";
|
||||
|
||||
const prod = process.argv[2] === "production";
|
||||
|
||||
const context = await esbuild.context({
|
||||
entryPoints: ["src/main.ts"],
|
||||
bundle: true,
|
||||
external: ["obsidian", "electron", "@codemirror/*", "@lezer/*"],
|
||||
format: "cjs",
|
||||
target: "es2021",
|
||||
logLevel: "info",
|
||||
sourcemap: prod ? false : "inline",
|
||||
treeShaking: true,
|
||||
outfile: "main.js",
|
||||
});
|
||||
|
||||
if (prod) {
|
||||
await context.rebuild();
|
||||
process.exit(0);
|
||||
} else {
|
||||
await context.watch();
|
||||
}
|
||||
|
|
@ -4,8 +4,8 @@
|
|||
"description": "Read FictionBook (.fb2) files directly in Obsidian.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "node esbuild.config.mjs",
|
||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production"
|
||||
"dev": "esbuild src/main.ts --bundle --external:obsidian --format=cjs --target=es2021 --outfile=main.js --sourcemap=inline --watch",
|
||||
"build": "tsc -noEmit -skipLibCheck && esbuild src/main.ts --bundle --external:obsidian --format=cjs --target=es2021 --outfile=main.js"
|
||||
},
|
||||
"keywords": [
|
||||
"obsidian",
|
||||
|
|
|
|||
654
src/main.ts
654
src/main.ts
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue