1.4.0

Added (#390)

  • Управление шириной side-панели чата (#390): в заголовок split-view-панели («Избранное»/«Задачи»/«Данные»/«Размышления»), слева от «Закрыть», добавлены две иконки-кнопки. «Развернуть на половину» снимает clamp 720px и раскрывает панель на настоящие 50% области чата (актуально на широких окнах — 1920px/2560px, где стандартная ширина упирается в max-width: 720px); кнопка рендерится только когда у неё есть эффект — родитель (body-row, т.е. область чата уже без фиксированного сайдбара) шире 2×720px, порог отслеживается ResizeObserver в $effect (синхронное начальное значение через untrack, гвард равенства против 60Гц-перерисовок, snap-back из half в default при сужении ниже порога — режим не «залипает» без кнопки). «Полный экран» раскрывает панель на 100% области чата (видна на всём десктопе ≥768px); повторный клик возвращает прежний режим (prevMode: half → full → half), Esc из полного экрана — тоже шаг назад, а не закрытие (ступенчатый Esc по образцу onescape-возврата от файла к дереву в «Данных»). CSS: режимы .side-panel-open.side-panel-half/.side-panel-full — составные селекторы перебивают .side-panel-open специфичностью и снимают clamp только пока панель открыта, поэтому закрытие из half/full анимируется в 0 как обычно; обе кнопки на мобильном (<768px) скрыты через CSS — там панель и так полноэкранный оверлей. Иконки — inline SVG (chevrons-out/in, maximize/minimize) в стиле существующей кнопки-крестика, у всех трёх кнопок общий класс side-panel-iconbtn.

Docs (#390)

  • docs/features-matrix.md §18: строка «Управление шириной side-панели чата (#390)» — кнопки «50%»/«Полный экран», условия видимости, возврат режима, скрытие на мобильном.

Review (#390)

  • ocr review (2 прогона) — закрыты: high «lifecycle ResizeObserver» ($effect с cleanup вместо onMount, устойчив к позднему связыванию asideEl); medium «залипание half при сужении» (snap-back в RO-колбэке); medium «закрытие из half/full не анимируется» (составные селекторы .side-panel-open.side-panel-*); medium «Esc из полного экрана закрывает панель целиком» (ступенчатый возврат + тест); medium «магический порог 1440» (константы CLAMP_MAX_PX/EXPAND_THRESHOLD_PX с комментарием-связкой к CSS); medium/low прочие (гвард равенства в RO-колбэке, синхронное начальное значение после observe(), aria-hidden на close-иконке, уточнения комментариев). Отклонены с обоснованием: medium «порог не учитывает сайдбар» — посылка неверна, AppSidebar фиксирован (fixed), app-main несёт margin-left: var(--sidebar-width), поэтому body-row уже исключает сайдбар и порог честен для обоих его состояний (зафиксировано комментарием); medium «stale prevMode при переоткрытии» — при закрытии панель размонтируется ({#if sidePanelKind()}) и state сбрасывается, сохранение ширины при смене вкладок в открытой панели — осознанное поведение единого каркаса; medium/low «disabled-кнопка и aria-live вместо скрытия» — противоречит утверждённому требованию «кнопка видна только когда есть эффект», live-анонсы в проекте не используются; low aria-expanded вместо aria-pressed — обе кнопки семантически toggle, aria-pressed корректен и консистентен; low «выжимание чат-колонки в full» — min-w-0 + overflow-hidden body-row исключают переполнение. Проверки: npm test (885), npm run check (0/0), npm run lint (единственная ошибка предсуществующая: WorkspaceMDViewer.svelte:247, воспроизводится на чистом дереве), make build-webui — зелёные; Go-код не менялся.