# SharedDocsLib SharedDocsLib — небольшой Python-фреймворк для документации. Страницы и HTML-компоненты описываются функциями с декораторами, а библиотека собирает Obsidian-подобный автономный клиент и отдаёт его через FastAPI. ## Возможности - страницы с номерами `1`, `1.1`, `1.1.2` и автоматическим деревом; - собственные `@Component` и набор безопасных базовых компонентов; - поиск по всему контенту, светлая/тёмная тема, breadcrumbs, Previous/Next; - изображения из `assets_dir`, единожды закодированные в base64 внутри manifest; - полностью автономный `index.html`: CSS, JavaScript и начальный manifest встроены; - хранение manifest в IndexedDB и одна проверка обновления при загрузке; - `index.zip`, содержащий только `index.html`; - live-preview с перекомпиляцией изменившегося Python-модуля. UI не содержит языко-зависимых служебных подписей: поиск, тема и мобильные меню обозначены пиктограммами, а в статусе показываются ISO-дата manifest и короткий `revision`. Светлая палитра нейтральная, тёмная использует настоящий AMOLED-чёрный. На мобильных устройствах header-кнопки открываются в отдельном правом drawer высотой `100dvh`. ## Установка из Git ```bash uv venv source .venv/bin/activate uv pip install "git+https://git.snw.su/snw/SharedDocsLib.git@main" ``` Для разработки и запуска примера из клонированного репозитория: ```bash uv sync --extra dev uv run python examples/basic.py ``` После запуска доступны: - `GET http://127.0.0.1:1234/manifest.json` - `GET http://127.0.0.1:1234/index.html` - `GET http://127.0.0.1:1234/index.zip` - `GET http://127.0.0.1:1234/live` (только при `live_preview=True`) ## Минимальный пример ```python from docslib import HeaderButton, run from docslib.hooks import Component, Page from docslib.components import H1, Image, LocalLink, P @Component def Lead(text): return f'
{text}
' @Page("1.", "Page title") def page1(): return [ H1("Hello"), P("Documentation text"), Image("photo.png", "Description"), LocalLink("Open nested page", subpage1), ] @Page("1.1", "Sub-page") def subpage1(): return [H1("Nested page")] if __name__ == "__main__": run( port=1234, host="0.0.0.0", title="My docs", assets_dir="./assets", custom_css="./assets/inject.css", manifest_path="http://127.0.0.1:1234/", live_preview=True, header_buttons=[ HeaderButton("Знакомство", page1), HeaderButton("API reference", subpage1), HeaderButton.external("Project", "https://example.com") ], ) ``` `manifest_path` принимает полный путь к JSON либо базовый URL, к которому будет добавлен `manifest.json`. Для совместимости также принят вариант `manifest_parh` из первоначального API, но в новом коде лучше использовать правильное имя. ## Компоненты Доступны `H1`, `H2`, `H3`, `P`, `MarkdownText`, `Image`, `Link`, `LocalLink` (`LocLink`), `Code`, `InlineCode`, `Quote`, `Callout`, `List`, `Table`, `Divider`, `Badge`, `Details`, `Json` и `RawHTML`. Обычные компоненты экранируют пользовательский текст. `RawHTML` и HTML из собственных `@Component` считаются доверенными и вставляются как есть. Функция страницы может вернуть строку, список/генератор строк, вложенные списки или `None`. ### Ссылки между страницами `LocalLink` создаёт обычную браузерную ссылку с hash-route. Поэтому ссылку можно копировать, открывать в новой вкладке и активировать с клавиатуры. Клиент перехватывает только обычный клик и показывает нужную страницу без перезагрузки. ```python # По объекту функции страницы — предпочтительный вариант: LocalLink("Установка", install_page) # По точному номеру: LocalLink("Установка", "1.2") # По уникальному названию: LocalLink("Установка", "Install") # По названию внутри раздела, если названия повторяются: LocalLink("Установка для сервера", "Install", section="2") ``` Цель по функции разрешается во время компиляции, когда все `@Page` уже зарегистрированы, поэтому можно ссылаться и на функцию, объявленную ниже по файлу. Если название неоднозначно или страница отсутствует, компиляция завершится понятной ошибкой. `LocLink` является коротким псевдонимом `LocalLink`. ### Ключевые кнопки в header Для навигации верхнего уровня используйте `HeaderButton`. Локальная цель поддерживает те же варианты, что и `LocalLink`: объект функции страницы, номер, уникальный заголовок или заголовок внутри указанного раздела. ```python run( header_buttons=[ # Короткая форма по функции страницы: HeaderButton("Знакомство", introduction_page), # Явная форма по номеру: HeaderButton.local("API reference", "3"), # По названию в определённом разделе: HeaderButton.local("Установка", "Install", section="2"), # Внешняя ссылка: HeaderButton.external("GitHub", "https://github.com/example/project"), ] ) ``` Локальная header-кнопка компилируется в обычный `href="#/page/…"`, открывает страницу без перезагрузки и подсвечивается на всех вложенных страницах своего раздела. Старые словари остаются совместимыми: ```python header_buttons=[ {"label": "Знакомство", "page": introduction_page}, {"label": "API", "page": "API reference", "section": "3"}, {"label": "GitHub", "href": "https://github.com/", "target": "_blank"}, ] ``` ## Manifest Manifest имеет версию схемы, заголовок, `revision`, `updated_at`, страницы, настройки UI и словарь ресурсов: ```json { "schema_version": 1, "title": "My docs", "revision": "…", "updated_at": "…", "pages": [{"number": "1", "title": "Home", "content": "