diff --git a/.github/workflows/gohugo.yml b/.github/workflows/gohugo.yml index 9a1e10a..ff0b873 100644 --- a/.github/workflows/gohugo.yml +++ b/.github/workflows/gohugo.yml @@ -1,160 +1,197 @@ name: Deploy Hugo site to Pages + on: push: branches: ["main"] + paths-ignore: + - "README.md" + - "LICENSE" + - ".gitignore" + - "docs/**" workflow_dispatch: + inputs: + force_regen: + description: "Пересобрать все артефакты, игнорируя кеш" + type: boolean + default: false + permissions: contents: read pages: write id-token: write -concurrency: - group: "pages" - cancel-in-progress: false + defaults: run: shell: bash + +env: + HUGO_VERSION: "0.161.1" + PANDOC_VERSION: "3.10.1" + TECTONIC_VERSION: "0.15.0" + jobs: - build: + build-deploy: runs-on: ubuntu-latest - env: - HUGO_VERSION: 0.161.1 + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + concurrency: + group: pages-${{ github.ref }} + cancel-in-progress: true + steps: - - name: Install Hugo CLI - run: | - wget -O ${{ runner.temp }}/hugo.deb \ - https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \ - && sudo dpkg -i ${{ runner.temp }}/hugo.deb + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 - - name: Install Dart Sass + - name: Определить, нужна ли генерация артефактов + id: changes run: | - sudo apt-get update -q - sudo apt-get install -y -q sass + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]] \ + || ! git rev-parse --verify -q HEAD^ >/dev/null; then + echo "content=true" >> "$GITHUB_OUTPUT"; exit 0 + fi + FILES=$(git diff --name-only HEAD^ HEAD) + echo "Изменённые файлы:"; echo "$FILES" + if grep -qE '^(content/|scripts/|\.github/workflows/)' <<< "$FILES"; then + echo "content=true" >> "$GITHUB_OUTPUT" + else + echo "content=false" >> "$GITHUB_OUTPUT" + fi + + - name: Собрать контрибьюторов + env: + GITHUB_TOKEN: ${{ github.token }} + run: python3 scripts/collect-contributors.py + + - name: Снапшот контрибьюторов в артефакты прогона + uses: actions/upload-artifact@v4 + with: + name: contributors-${{ github.run_number }} + path: data/contributors.json + retention-days: 90 - - name: Cache apt-пакеты + - name: Restore артефактов генераторов + id: gen-cache + uses: actions/cache/restore@v4 + with: + path: | + .cache + static/covers + static/posts + key: gen-${{ github.sha }} + restore-keys: gen- + + - name: Решить, запускать ли генераторы + id: gen + run: | + NEED=false + [[ "${{ steps.changes.outputs.content }}" == "true" ]] && NEED=true + # кеш вообще не восстановился — артефактов нет, надо генерить + [[ -z "${{ steps.gen-cache.outputs.cache-matched-key }}" ]] && NEED=true + [[ "${{ inputs.force_regen }}" == "true" ]] && NEED=true + echo "run=$NEED" >> "$GITHUB_OUTPUT" + echo "Генераторы: $NEED" + + - name: Cache CLI-бинарников + id: bins uses: actions/cache@v4 with: - path: /var/cache/apt/archives/*.deb - key: apt-xetex-v1-${{ runner.os }} + path: ~/.local/bin + key: bins-${{ runner.os }}-h${{ env.HUGO_VERSION }}-p${{ env.PANDOC_VERSION }}-t${{ env.TECTONIC_VERSION }} - - name: Install pandoc + XeLaTeX + - name: Скачать hugo / pandoc / tectonic + if: steps.bins.outputs.cache-hit != 'true' run: | - sudo apt-get install -y -q \ - pandoc \ - texlive-xetex \ - texlive-lang-cyrillic \ - fonts-dejavu + set -euo pipefail + mkdir -p ~/.local/bin && cd "$(mktemp -d)" - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: recursive + curl -sSL "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz" \ + | tar xz hugo && mv hugo ~/.local/bin/ - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'npm' + curl -sSL "https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pandoc-${PANDOC_VERSION}-linux-amd64.tar.gz" \ + | tar xz --strip-components=2 "pandoc-${PANDOC_VERSION}/bin/pandoc" && mv pandoc ~/.local/bin/ - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' + curl -sSL "https://github.com/tectonic-typesetting/tectonic/releases/download/tectonic%40${TECTONIC_VERSION}/tectonic-${TECTONIC_VERSION}-x86_64-unknown-linux-musl.tar.gz" \ + | tar xz tectonic && mv tectonic ~/.local/bin/ - - name: Install Python dependencies - run: pip install Pillow pyyaml genanki + chmod +x ~/.local/bin/* - - name: Cache fonts - uses: actions/cache@v4 - with: - path: .cache/fonts - key: covers-fonts-v1 + - name: PATH + run: echo "$HOME/.local/bin" >> "$GITHUB_PATH" - - name: Cache cover markers + - name: Cache бандла tectonic + if: steps.gen.outputs.run == 'true' uses: actions/cache@v4 with: - path: .cache/covers - key: covers-markers-${{ github.sha }} - restore-keys: covers-markers- + path: ~/.cache/Tectonic + key: tectonic-bundle-${{ env.TECTONIC_VERSION }}-v1 - - name: Cache PDF хеши - uses: actions/cache@v4 + - name: Setup Python + if: steps.gen.outputs.run == 'true' + uses: actions/setup-python@v5 with: - path: | - .cache/pdf - static/posts/*/resources/*.pdf - key: pdf-v1-${{ hashFiles('content/posts/**/*.md') }} - restore-keys: pdf-v1- + python-version: "3.12" + cache: pip + cache-dependency-path: scripts/requirements.txt - - name: Cache AI merged хеши - uses: actions/cache@v4 - with: - path: | - .cache/ai - static/posts/*/resources/*_merged.md - key: ai-v1-${{ hashFiles('content/posts/**/*.md') }} - restore-keys: ai-v1- + - name: Python deps + if: steps.gen.outputs.run == 'true' + run: pip install -r scripts/requirements.txt - - name: Cache Anki хеши - uses: actions/cache@v4 + - name: Генерация (covers / anki / merged / pdf) + if: steps.gen.outputs.run == 'true' + run: | + python scripts/generate-covers.py + python scripts/generate-anki.py + python scripts/merge-md-for-ai.py + python scripts/generate-pdf.py --jobs "$(nproc)" + + - name: Save артефактов генераторов + if: steps.gen.outputs.run == 'true' + uses: actions/cache/save@v4 + continue-on-error: true with: path: | - .cache/anki - static/posts/*/resources/*.apkg - static/posts/*/*/resources/*.apkg - key: anki-v1-${{ hashFiles('content/posts/**/*.md', 'content/posts/**/*.csv') }} - restore-keys: anki-v1- - - - name: Generate OG covers - run: python scripts/generate-covers.py - - - name: Generate Anki decks - run: python scripts/generate-anki.py - - - name: Generate merged MD for AI - run: python scripts/merge-md-for-ai.py - - - name: Generate PDF конспекты - run: python scripts/generate-pdf.py + .cache + static/covers + static/posts + key: gen-${{ github.sha }} - name: Setup Pages id: pages uses: actions/configure-pages@v5 - - name: Install Node.js dependencies and build CSS + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: npm + + - name: Build CSS run: | - npm ci + npm ci --prefer-offline --no-audit --fund=false npm run css - name: Build with Hugo env: HUGO_CACHEDIR: ${{ runner.temp }}/hugo_cache HUGO_ENVIRONMENT: production - run: | - hugo \ - --minify \ - --baseURL "${{ steps.pages.outputs.base_url }}/" + run: hugo --gc --minify --baseURL "${{ steps.pages.outputs.base_url }}/" - name: Verify build run: | - [ -f public/index.html ] || exit 1 - grep -q "
/dev/null 2>&1 || \ - (echo "Обложки не попали в public/covers/!"; exit 1) - echo "Содержимое index.html проверено." - echo "Обложки на месте." + [ -s public/index.html ] || { echo "index.html пустой"; exit 1; } + grep -q "/dev/null 2>&1 || { echo "Обложки не попали в public/covers/"; exit 1; } - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: ./public - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 \ No newline at end of file + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..ed1c0da --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,99 @@ +# Проверка Pull Request. +# +# Ничего не публикует — только говорит, соберётся ли сайт и не сломает ли +# правка что-нибудь ещё. Деплой остаётся в отдельном workflow на main. +# +# Задачи разнесены намеренно: автор PR должен видеть, что именно не так, +# а не «один красный крестик». + +name: PR + +on: + pull_request: + branches: [main] + +# Новый пуш в ту же ветку отменяет предыдущий прогон. +concurrency: + group: pr-${{ github.event.pull_request.number }} + cancel-in-progress: true + +permissions: + contents: read + +env: + HUGO_VERSION: 0.161.1 + +jobs: + # ── 1. Front matter и структура папок ────────────────────────────────── + content: + name: Конспекты + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - run: pip install pyyaml + + - name: Проверить структуру и front matter + run: python scripts/check-content.py + + # ── 2. Собирается ли сайт ────────────────────────────────────────────── + build: + name: Сборка + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # нужна полная история для контрибьюторов + submodules: recursive + + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: npm + + - name: Установить Hugo + run: | + wget -qO hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb + sudo dpkg -i hugo.deb + + # Аватарки и пережатые картинки переживают прогоны — иначе каждая + # сборка заново ходит на github.com. + - name: Кеш ресурсов Hugo + uses: actions/cache@v4 + with: + path: | + resources/_gen + /tmp/hugo_cache + key: hugo-${{ runner.os }}-${{ hashFiles('content/**/*.md', 'hugo.toml') }} + restore-keys: hugo-${{ runner.os }}- + + - run: npm ci + - run: npm run build + + - name: Собрать контрибьюторов + run: python scripts/collect-contributors.py + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # --printPathWarnings ловит коллизии адресов: две лекции с одним + # слагом молча перетирают друг друга, если на них не смотреть. + - name: Hugo build + run: hugo --gc --minify --printPathWarnings --baseURL "/" + + - name: Отчёт о размере + run: | + echo "### Размер сборки" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + du -sh public >> $GITHUB_STEP_SUMMARY + find public -name '*.html' | wc -l | xargs echo "HTML страниц:" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + + - uses: actions/upload-artifact@v4 + with: + name: site + path: public + retention-days: 7 diff --git a/.gitignore b/.gitignore index 54f2068..bcb72e5 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ .hugo_build.lock output.css +contributors.json /public /resources/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..64eaa32 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,101 @@ +# Changelog + +Формат — [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/). +Версионируется движок сайта: шаблоны, стили, скрипты и **формат front matter**. +Публикация конспектов версией не отмечается. + +Что считается мажорным изменением: контент, написанный по старым правилам, перестаёт корректно собираться или отображаться. + +## [3.0.0] — 2026-08-XX + +Крупный рефакторинг: несколько конспектов на один предмет, формулы и иконки переехали на этап сборки, сторонние CDN убраны из критического пути. + +### Добавлено + +- **Несколько конспектов у одного предмета.** Одна папка описывает вариант: преподаватель + автор + учебный год. Варианты связываются ключом `subject`, на главной это одна карточка с раскрывающимся списком, внутри курса — переключатель с запоминанием выбора в `localStorage`. +- **Учебный год** (`academicYear`) у курсов и лекций. Если у того же преподавателя есть запись за более свежий год, старая помечается, а на её странице появляется ссылка на новую. +- Метка происхождения конспекта (`noteType`) с моделью и источником в подсказке. +- Общие подсказки: атрибут `data-cn-tip` на любом элементе. +- Контрибьюторы в футере с аватарками и статистикой коммитов. +- Проверка Pull Request в CI: front matter по схеме из архетипов, сборка, битые ссылки, формат заголовка. +- Архетипы для новых конспектов, курсов и отдельных страниц. +- Партиал `ui/icon.html` и шорткод `{{< icon >}}` — иконки инлайном. +- Шрифты, KaTeX и иконки вендорятся скриптом `scripts/vendor-assets.sh` и хранятся в репозитории. + +### Изменено + +- **Формулы считаются на сборке** через `transform.ToMath` (KaTeX внутри Hugo) вместо MathJax на клиенте. Требуется Hugo ≥ 0.132 и блок `passthrough` в конфиге. +- **Шрифты раздаются со своего домена** вместо `fonts.googleapis.com`. +- Цвет курса задаётся единственным полем `accent` и наследуется внутрь: карточка, шапка, обложки лекций, сайдбары. Раньше выбирался случайно по хешу заголовка. +- Аватарки GitHub скачиваются и пережимаются на этапе сборки. +- Левый и правый сайдбары лекции приведены к одному виду. +- Тема переключается только системными настройками ОС; отдельная логика ручного переключения убрана. +- Поисковый индекс грузится лениво — при первом фокусе на поле, а не на загрузке страницы. +- В индексе одна запись на предмет вместо записи на каждую папку; в текст попали фамилии преподавателей, авторы и год. +- Подсветка активного пункта в оглавлении переведена на `IntersectionObserver` вместо `scroll` с debounce. +- Контекстное меню и виджет-помощник грузятся лениво. +- Единая функция русской плюрализации вместо трёх разных. +- Порядок лекций согласован между списком, сайдбаром, «предыдущая/следующая» и нумерацией на обложках. +- Обновлены и приведены к единому стилю существующие markdown-файлы конспектов. +- daisyUI обновлён до v5.7.16, ai-widget переведён на его кастомные свойства. + +### Удалено + +- **MathJax** — 260 КБ JS и до 442 КБ шрифтов с сетевого пути. +- **Alpine.js** (16 КБ) — на нём держались только шорткоды `tabs`/`tab`, они удалены вместе с ним. +- **Ionicons как веб-компонент** — 24 КБ рантайма и по одному HTTP-запросу на каждую иконку (на странице курса их 11). +- Masonry. +- Остатки темы Dream, мёртвый CSS (`list.css`, disqus, `flip-container`, `dream-alert`) и осиротевшие партиалы. + +### Исправлено + +- Устаревшие вызовы Hugo: `site.Data` → `.Data`, `site.Language.LanguageCode` → `.Language.Locale`. +- Сортировка секций по дате и весу. +- Выравнивание и отступы текста на обложках. +- Наложение аватарок в списке авторов. +- Суффикс с названием сайта на странице 404. +- Вёрстка страницы лекции не сдвигается при скрытом сайдбаре. + +### Сломано + +- Курс с несколькими преподавателями нужно разложить по отдельным папкам и проставить `subject`. Развести преподавателей внутри одной папки полем у лекции больше нельзя. +- Обложки лекций не раскрашиваются хешем от заголовка — цвет приходит от `accent` курса. +- `cover_style` больше ни на что не влияет. +- Одиночный `$` остаётся инлайн-разделителем формул, но парсер стал строгим: пара обычных долларов в одном абзаце (`цена 5$ и 10$`) покрасится в красный, нужно экранировать `\$`. +- Новая иконка требует прогона `scripts/vendor-assets.sh` — иначе на её месте пустое место и предупреждение в логе сборки. + +### Замеры + +Ушло с сетевого пути (gzip): MathJax 260 КБ + до 442 КБ шрифтов, Alpine 16 КБ, ionicons 24 КБ и запрос на иконку, два RTT до Google за шрифтами. Добавилось: KaTeX CSS 3,5 КБ, и только на страницах с формулами. + +В репозиторий добавилось 248 КБ текстовых шрифтов, 254 КБ шрифтов KaTeX и 15 КБ иконок; браузер качает из этого единицы файлов благодаря `unicode-range` и подмножествам глифов. + +Цена для сборки — около 0,085 мс на формулу: на тестовом сайте 130 мс без формул против 164 мс с четырьмястами формулами на одной странице. + +## [2.0.0] + +Полная переработка контента и оформления после первой версии: сайт отвязан от темы Dream, появились поиск, шорткоды и автогенерация сопутствующих материалов. + +### Добавлено + +- Поиск по сайту, разбиение на разделы, разделение курсов по семестрам. +- Лекции: операционные системы, базы данных, C++ (семестр 1 и 2), математическая статистика. +- Автогенерация OG-картинок, Anki-колод и контекста для ИИ (`llm-context`) в CI/CD. +- Шорткоды для разметки лекций. +- Виджет с ИИ-помощником, кастомное контекстное меню. +- Новый логотип. + +### Изменено + +- Сайт полностью отвязан от темы Dream — собственные layout'ы вместо темы. +- Несколько итераций редизайна вёрстки и мобильного вида (шапка, списки, Anki-страницы). +- CI/CD-воркфлоу переработан и оптимизирован: кеширование и tectonic. + +## [1.0.0] + +Первая версия сайта на теме Dream. + +### Добавлено + +- Hugo-сайт на теме Dream, публикация через GitHub Actions. +- Подсветка синтаксиса кода. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c2e2c55..67720f0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,170 +1,278 @@ # Контрибьютинг -Этот документ описывает, как внести правки в репозиторий: структуру файлов, front matter, шорткоды и процесс отправки Pull Request. Перед началом работы рекомендуется ознакомиться с [README.md](README.md). +Структура файлов, front matter, проверки и процесс Pull Request. -## Способы участия +## С чего начать -### 1. Сообщить об ошибке +| Что хотите сделать | Куда идти | +|---|---| +| Нашли ошибку, править не готовы | [Issue](https://github.com/botaemeveryday/notes/issues/new?template=content-error.md) | +| Поправить текст лекции | `content/posts/<курс>/<лекция>/index.md` → PR | +| Добавить лекцию | новая папка в существующем курсе | +| Добавить курс | новая папка в `content/posts/` с `_index.md` | +| Свои конспекты по курсу, который уже есть | отдельная папка + общий `subject`, см. [ниже](#несколько-конспектов-по-одному-предмету) | -Если вы заметили проблему, но не готовы исправлять её самостоятельно — откройте [Issue](https://github.com/botaemeveryday/notes/issues/new?template=content-error.md). Подходящие поводы: +Последний случай — самый частый и самый важный. **Не смешивайте записи разных преподавателей, авторов или годов в одной папке.** Одна папка — один вариант конспекта. -- Ошибка в тексте, формуле или коде. -- Битое изображение или проблема с рендерингом. -- Неточность в объяснении или фактическая ошибка. -- Предложение по улучшению структуры или подачи материала. +## Локальная сборка -### 2. Исправить или дополнить существующий конспект +Требования: Hugo **extended ≥ 0.132** (формулы считаются на сборке, раньше не заработает), Node.js, npm, Python 3.11+, Git. -1. Найдите нужную лекцию в `content/posts/<курс>/<лекция>/index.md`. -2. Внесите правки, соблюдая правила оформления (см. ниже). -3. Проверьте результат локально (`hugo server -D`). -4. Отправьте Pull Request. +```bash +git clone https://github.com/botaemeveryday/notes.git +cd notes -### 3. Добавить новую лекцию +npm install # Tailwind и зависимости +npm run build # сборка стилей +hugo server -D # http://localhost:1313 +``` + +Шрифты, KaTeX и иконки лежат в репозитории — качать ничего не нужно. + +`npm run build` перезапускайте после появления новых Tailwind-классов, иначе они не попадут в CSS. **Если правку видно в разметке, но не видно на странице — начинайте отсюда.** + +Перед отправкой PR: ```bash -mkdir -p content/posts/<курс>/<идентификатор-лекции>/images -touch content/posts/<курс>/<идентификатор-лекции>/index.md +pip install pyyaml +python scripts/check-content.py # то же, что проверит CI +python scripts/check-content.py --strict # ещё и предупреждения ``` -Минимальный `index.md`: +## Именование + +| Объект | Соглашение | Примеры | +|---|---|---| +| Папка курса | `kebab-case` | `databases`, `operation-systems` | +| Папка варианта | `<предмет>-<фамилия>` | `java-makarevich`, `java-butenko` | +| Папка варианта с автором | `<предмет>-<фамилия>-<автор>` | `java-makarevich-notakeith` | +| Папка лекции | `kebab-case` | `lecture-01` | +| Изображения | осмысленное имя | `cover.png`, `process-tree.png` | + +Внутри одного курса держитесь единого стиля нумерации лекций — либо `lecture-01`, либо тематического `allocator-02-26`. Не смешивайте. + +``` +content/posts/<курс>/<лекция>/ +├── index.md +└── images/ + └── process-tree.png +``` + +## Front matter лекции ```yaml --- title: "Название лекции" -description: "Краткое описание содержания" +description: "Короткое описание, 1–2 предложения" date: 2026-05-07 +weight: 3 # номер лекции tags: - - C++ - - 2 семестр + - Базы данных + - 4 семестр + +authors: [] # если автор лекции отличается от автора курса +noteType: human # human | ai | ai-pro +aiModel: "" +aiSource: "" --- ``` -### 4. Добавить новый курс +Обязателен `title` и **либо** `date`, **либо** `weight` — иначе проверка PR не пройдёт. -1. Создайте директорию `content/posts/<курс>/`. -2. Положите в неё `_index.md` с описанием курса (см. соседние курсы как образец). -3. Добавьте `cover.png` для секции. -4. Создавайте лекции по схеме выше. +`weight` задаёт номер лекции на обложке. Без него номер считается по позиции в списке: для сплошного курса это нормально, но ломается, когда лекции добавляют не по порядку. -## Локальная сборка +`draft: true` скрывает страницу. В PR его лучше не оставлять. -Требования: Hugo (extended), Node.js, npm, Git. +### Метка происхождения -```bash -git clone https://github.com/botaemeveryday/notes.git -cd notes +| `noteType` | Метка | Когда ставить | +|---|---|---| +| `human` | Авторский (зелёная) | Написан человеком. Если ИИ помогал с оформлением — метка та же, но заполните `aiModel`, это честнее | +| `ai` | Нейроконспект (янтарная) | Сгенерирован моделью по аудио или презентации | +| `ai-pro` | Нейроконспект (фиолетовая) | То же, но моделью повышенной точности | -npm install # установка Tailwind и зависимостей -npm run build # сборка стилей -hugo server -D # http://localhost:1313 -``` +Для `ai` и `ai-pro` заполняйте `aiModel` и `aiSource` — иначе читатель не поймёт, чему доверяет. Оба попадают в подсказку при наведении на метку. + +`noteType` наследуется: если у лекции его нет, берётся из `_index.md` курса. + +## Front matter курса (`_index.md`) -`npm run build` нужно перезапускать после добавления новых Tailwind-классов, которых ещё не было в проекте — иначе классы не попадут в итоговый CSS. +```yaml +--- +title: "Базы данных" +description: "Реляционная модель, нормализация, индексы, транзакции." +semester: 4 +accent: 3 # 1..6 — цвет курса +weight: 10 # порядок в списке и порядок вариантов + +teacher: "Мацнев Николай Игоревич" +author: "notakeith" # или authors: [...] +academicYear: 2025 # → «2025/26» + +subject: "databases" # только если вариантов несколько +noteType: human # метка по умолчанию для всех лекций курса +abbr: "" # аббревиатура на карточке, иначе по инициалам +tag: "" # маленькая плашка на карточке +--- +``` -## Правила оформления +`accent` — **единственный источник цвета**. Он красит карточку на главной, шапку курса, обложки всех лекций и сайдбары. Точечно переопределить можно у лекции через `cover_color` и `cover_color_soft`, но без нужды не стоит. -### Именование +`author` понимает и ник GitHub (`notakeith` → аватарка и ссылка подтянутся сами), и обычное имя, и список: -| Объект | Соглашение | Примеры | -|---|---|---| -| Папка курса | `kebab-case` | `database-design`, `operation-systems` | -| Папка лекции | `kebab-case` | `lecture-01` | -| Изображения | произвольное имя, желательно осмысленное | `cover.png`, `process-tree.png` | +```yaml +authors: + - notakeith + - name: "Пётр Петров" + github: "petrov" +``` -В рамках одного курса придерживайтесь единого стиля именования лекций — либо нумерованного (`lecture_01`, `lecture_02`), либо тематического (`allocator-02-26`, `casts-04-02`). Не смешивайте. +## Несколько конспектов по одному предмету -### Структура папки лекции +Одна папка — один вариант. Вариант определяется тремя вещами: **преподаватель, автор конспекта, учебный год**. Варианты склеиваются общим ключом `subject`: ``` -content/posts/<курс>/<лекция>/ -├── index.md # текст лекции -└── images/ - ├── cover.png # обложка (обязательно) - └── ... # остальные изображения +content/posts/java-makarevich-notakeith/_index.md + title: Java subject: java teacher: Макаревич Р. Д. author: notakeith academicYear: 2025 weight: 10 + +content/posts/java-makarevich-petrov/_index.md + title: Java subject: java teacher: Макаревич Р. Д. author: Петров К. academicYear: 2025 weight: 20 + +content/posts/java-butenko-notakeith/_index.md + title: Java subject: java teacher: Бутенко А. В. author: notakeith academicYear: 2024 weight: 30 ``` -### Front matter +На главной это **одна** карточка «Java». Она раскрывается списком вариантов: преподаватель, метка происхождения, автор, число лекций, учебный год. Внутри курса кнопка открывает выбор, выбор запоминается в браузере — следующий клик по предмету на главной откроет его же. + +Требования: + +- у всех вариантов одного `subject` совпадают `title`, `accent`, `semester`; +- у каждого варианта заполнены `teacher` и `author`; +- `weight` задаёт порядок вариантов. Без него порядок определяется фамилией и годом — предсказуемо, но не факт что так, как вам хочется. -Обязательные поля: +Заголовок предмета берётся из варианта с наименьшим `weight`. Если папки называются по-разному, а показать надо одно название — поставьте `subjectTitle` любому из вариантов. + +### Учебный год ```yaml ---- -title: "Название лекции" -description: "Короткое описание (1–2 предложения)" -date: 2026-05-07 -tags: - - 0 Семестр - - Название курса ---- +academicYear: 2025 # → 2025/26 +academicYear: "2025/26" # так тоже можно ``` -`draft: true` скрывает страницу из публикации — используется для незавершённых материалов. +Год виден плашкой рядом с преподавателем. Если у **того же самого** преподавателя есть конспект за более свежий год, старый помечается приглушённой плашкой, а на его странице появляется баннер со ссылкой на новый. Сравнение идёт строго внутри преподавателя — разные лекторы с разными годами друг друга не «устаревают». -### Изображения +Год необязателен, но без него эта механика не работает. -- Поддерживаемые форматы: PNG, JPG, SVG, WebP. -- Хранятся в `images/` внутри папки лекции. -- Рекомендуется сжимать растровые изображения (например, через [squoosh.app](https://squoosh.app) или `oxipng`). -- Файл `cover.png` обязателен для каждой лекции. +## Формулы -### Формулы и код +Синтаксис LaTeX, считаются **на сборке** через KaTeX. На клиенте JS для формул больше не грузится. -- Математика — через MathJax, синтаксис LaTeX: `$inline$` и `$$display$$`. -- Блоки кода — с указанием языка для подсветки: ` ```cpp `, ` ```python ` и т. д. -- Mermaid-диаграммы — через стандартный блок ` ```mermaid `. +``` +$inline$ \(inline\) +$$display$$ \[display\] +``` -### Шорткоды +Блок ` ```math ` — то же самое display-формулой. -В проекте определены готовые шорткоды (`layouts/shortcodes/`), используйте их вместо ручной HTML-разметки: +**Ловушка с долларом.** Одиночный `$` — инлайновый разделитель, поэтому пара обычных долларов в одном абзаце превратится в формулу и покрасится в красный: + +``` +цена 5$ и 10$ ← сломается +цена 5\$ и 10\$ ← правильно +``` + +Ошибка в формуле не роняет сборку — KaTeX красит её красным прямо на странице. Проверяйте локально. + +## Код, изображения, диаграммы + +- Блоки кода — обязательно с языком: ` ```cpp `, ` ```python `. +- Диаграммы — ` ```mermaid `. +- Изображения: PNG, JPG, SVG, WebP, лежат в `images/` внутри папки лекции. Растр сжимайте — [squoosh.app](https://squoosh.app) или `oxipng`. + +## Иконки + +Иконки вставляются в разметку на сборке, никакого JS. В тексте лекции: + +``` +{{< icon "download-outline" >}} +{{< icon name="warning-outline" class="text-warning" >}} +``` + +Имена — из [ionicons](https://ionic.io/ionicons). **Если нужной иконки ещё нет в `assets/icons/`**, сборка выведет предупреждение, а на её месте будет пусто. Добавить: + +```bash +./scripts/vendor-assets.sh +``` + +Скрипт сам находит имена в шаблонах и контенте. Если имя вычисляется в шаблоне или приходит из front matter — впишите его в массив `EXTRA` внутри скрипта, грепом такое не находится. + +## Шорткоды + +Готовые шорткоды из `layouts/shortcodes/` вместо ручного HTML: | Шорткод | Назначение | |---|---| | `callout` | Выделенный блок (note, warning, tip) | | `card`, `cards` | Карточки для навигации | | `compare` | Сравнение двух вариантов бок о бок | -| `spoiler` | Скрытый блок с решением/ответом | -| `key` | Отображение клавиатурной комбинации | +| `spoiler` | Скрытый блок с решением | +| `key` | Клавиатурная комбинация | +| `marker`, `hand` | Выделение маркером, «рукописная» вставка | +| `math-box` | Теорема, определение, доказательство | +| `step`, `timeline` | Пошаговые и хронологические списки | | `stat`, `stat-row` | Числовая статистика | -| `youtube` | Встраивание видео | -| `anki-download` | Ссылка на колоду Anki | +| `terminal`, `filetree` | Вывод консоли, дерево файлов | +| `trap`, `note`, `disclaimer` | Предупреждения и примечания | +| `icon` | Иконка | +| `godbolt`, `youtube`, `anki-download` | Встраивания | ## Pull Request -1. Сделайте форк репозитория. -2. Создайте ветку с осмысленным именем: `git checkout -b fix/cpp-exceptions`. -3. Внесите изменения и проверьте их локально. -4. Откройте Pull Request в `main`. - -### Формат коммитов и заголовка PR +```bash +git checkout -b fix/cpp-exceptions +# правки, проверка локально +``` -Проект придерживается [Conventional Commits](https://www.conventionalcommits.org/ru/v1.0.0/). Заголовок имеет вид: +Заголовок PR — [Conventional Commits](https://www.conventionalcommits.org/ru/v1.0.0/): ``` -' + text + '…
' + + '+ thanks to <3 +
+ +made by - + notakeith & - + salt-caramel
diff --git a/layouts/partials/header/logo.html b/layouts/partials/header/logo.html index f455b6d..30b57af 100644 --- a/layouts/partials/header/logo.html +++ b/layouts/partials/header/logo.html @@ -1,70 +1,11 @@ - - \ No newline at end of file + diff --git a/layouts/partials/header/nav.html b/layouts/partials/header/nav.html index a792427..29627b9 100644 --- a/layouts/partials/header/nav.html +++ b/layouts/partials/header/nav.html @@ -1,109 +1,64 @@ -{{ if site.Params.stickyNav }} -