feat(window): maximize toggle + drag-zone fix + minWidth bump

- Средняя кнопка тайтлбара теперь toggle maximize/restore (была
  hide-to-tray, но иконка Square вводила в заблуждение — выглядит
  как нативная maximize). Double-click по тайтлбару тоже работает.
- Иконка свапается Square ↔ Copy в зависимости от max-state,
  aria-label локализован (titlebar.maximize_aria / restore_aria).
- Новый IPC: toggleMaximizeMain, isMaximizedMain (invoke),
  evtMaximizeChanged (event main → renderer на maximize/unmaximize).
- Фикс drag-зоны: titlebar-nodrag перенесён с обёртки правого
  кластера на сами кнопки. Из-за flex-1 basis-0 пустое место слева
  от кнопок раньше было no-drag — окно нельзя было ухватить рядом.
- minWidth/minHeight окна 900x600 → 1100x700, чтобы Tailwind lg:
  всегда срабатывал (4 hero-stat в один ряд, heatmap без скролла).
- CLAUDE.md: контекст проекта для будущих сессий Claude Code
  (стек, архитектура, команды, релиз, тех. долг, чего не делать).
This commit is contained in:
AnRil
2026-05-19 17:52:54 +07:00
parent 2503b27d42
commit e96ca06587
7 changed files with 251 additions and 11 deletions

View File

@@ -176,6 +176,17 @@ export function registerIpc(): void {
BrowserWindow.fromWebContents(event.sender)?.minimize()
})
ipcMain.on(IPC.toggleMaximizeMain, (event) => {
const win = BrowserWindow.fromWebContents(event.sender)
if (!win) return
if (win.isMaximized()) win.unmaximize()
else win.maximize()
})
ipcMain.handle(IPC.isMaximizedMain, (event) => {
return BrowserWindow.fromWebContents(event.sender)?.isMaximized() ?? false
})
ipcMain.on(IPC.closeMain, () => {
const main = getMainWindow()
if (!main) return

View File

@@ -1,4 +1,5 @@
import { BrowserWindow, shell, screen, app, nativeImage } from 'electron'
import { IPC } from '../shared/ipc'
import { existsSync } from 'node:fs'
import { join } from 'node:path'
@@ -90,8 +91,13 @@ export function createMainWindow(showImmediately = true): BrowserWindow {
const win = new BrowserWindow({
width: 1100,
height: 720,
minWidth: 900,
minHeight: 600,
// Минимум подобран так, чтобы:
// - срабатывал Tailwind `lg:` (≥1024px) → 4 hero-stat в один ряд, а не 2×2
// - сайдбар (256px) + контент (max-w-5xl, padding lg:px-10) помещались без
// горизонтального скролла heatmap'а и карточек упражнений
// - по вертикали оставался запас на header + stats + heatmap без обрезки
minWidth: 1100,
minHeight: 700,
show: false,
frame: false,
backgroundColor: '#0f1117',
@@ -110,6 +116,16 @@ export function createMainWindow(showImmediately = true): BrowserWindow {
if (showImmediately) win.show()
})
// Сообщаем рендереру об изменении max-состояния, чтобы он мог менять
// иконку (квадрат ↔ «двойной квадрат») в кастомном тайтлбаре.
const emitMaxState = (maximized: boolean): void => {
if (!win.isDestroyed()) {
win.webContents.send(IPC.evtMaximizeChanged, maximized)
}
}
win.on('maximize', () => emitMaxState(true))
win.on('unmaximize', () => emitMaxState(false))
installSafeNavigation(win)
loadRoute(win, 'main')