diff --git a/docs/TZ.md b/docs/TZ.md
index e218094..9abc394 100644
--- a/docs/TZ.md
+++ b/docs/TZ.md
@@ -4,7 +4,7 @@
| | |
|---|---|
-| Версия ТЗ | 0.89 |
+| Версия ТЗ | 0.90 |
| Дата | 2026-10-10 |
| Статус | На обсуждении |
@@ -102,6 +102,17 @@
поля тоже показываются («— не указано») и редактируются кликом. То же — на
странице проекта (название, заметка, актуальность, приоритет). Полный режим
правки (вся форма целиком) сохраняется наряду с инлайном.
+ Открытие редактора ставит фокус в первое поле (клик по значению = «начать
+ печатать»), а Esc отменяет правку независимо от того, где сейчас фокус (0.90):
+ без этого Esc работал, только пока фокус оставался внутри редактора, — после
+ клика по соседней строке он молча перестаёт действовать.
+- **Длительность — часами и минутами** (0.90): оценка и факт вводятся двумя полями
+ («ч» и «мин»), а не переводом в минуты. Пока в полях печатают, они источник
+ истины: пришедшее от страницы значение применяется, только если не совпадает с
+ уже набранным (иначе очищенное поле мгновенно наполнялось прежним числом, и
+ переписать значение было нельзя). Границы — как у API (`1…1440` мин): выход из
+ полей сворачивает минуты в часы («0 ч 90 мин» → «1 ч 30 мин») и зажимает
+ значение, а не сервер отвечает 422 после нажатия ✓.
- **README вместо описания-ссылки** (0.41): если **описание задачи** состоит из
одной ссылки на git-репозиторий, вместо неё показывается `README.md` из
репозитория (с подписью-ссылкой на источник). Хост не обязан быть
@@ -841,6 +852,16 @@
- **Манифест**: standalone, тёмная палитра кита (`#16161e` — фон и theme-color,
чтобы не мигало белым при запуске и не зеленела шапка окна), иконки 192/512 +
maskable-512, `id`/`start_url` = `/`, язык ru.
+- **Иконки** (0.90): растрируются из лого скриптом `tools/rasterize_icons.sh` —
+ единственный источник, поэтому знак в шапке, иконка вкладки и иконка приложения
+ не разъезжаются. У скругления холста логотипа (`rx` 10 = 15% стороны) в иконках
+ «any» **углы прозрачные**: с впечатанным фоном скругление сливается с заливкой
+ холста, и иконка читается квадратом с острыми углами — в том числе в шторке
+ системных уведомлений (3.21), где она и была замечена владельцем. Эти же 192/512
+ отдаются уведомлению как `icon` (0.90). Где прозрачность недопустима, фон
+ впечатан: `apple-touch-icon.png` (180, iOS рисует прозрачность чёрным и обрезает
+ иконку своей маской — отдельный файл, а не 192 из «any») и `maskable-512.png`
+ (Android обрезает по кругу, холст в safe zone 80%).
- **Service Worker** (vite-plugin-pwa, `autoUpdate`; с 0.88 — свой воркер `src/sw.ts`,
стратегия `injectManifest`): precache оболочки — собранные ассеты, шрифты/иконки кита
(~6 МБ лимит), `/api/*`, `/auth/*`, `/mcp/*` никогда не кэшируются и не получают
diff --git a/frontend/index.html b/frontend/index.html
index 6d7fb99..11e6fee 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -10,7 +10,10 @@
-
+
+
GNexus Tasks
diff --git a/frontend/public/icons/apple-touch-icon.png b/frontend/public/icons/apple-touch-icon.png
new file mode 100644
index 0000000..cc6af26
--- /dev/null
+++ b/frontend/public/icons/apple-touch-icon.png
Binary files differ
diff --git a/frontend/public/icons/icon-192.png b/frontend/public/icons/icon-192.png
index 22cc9fe..3ed7578 100644
--- a/frontend/public/icons/icon-192.png
+++ b/frontend/public/icons/icon-192.png
Binary files differ
diff --git a/frontend/public/icons/icon-512.png b/frontend/public/icons/icon-512.png
index 36370a4..dc4419c 100644
--- a/frontend/public/icons/icon-512.png
+++ b/frontend/public/icons/icon-512.png
Binary files differ
diff --git a/frontend/src/components/DurationInput.vue b/frontend/src/components/DurationInput.vue
index 9aa69e7..53fb778 100644
--- a/frontend/src/components/DurationInput.vue
+++ b/frontend/src/components/DurationInput.vue
@@ -1,24 +1,42 @@
-
+ {{ label }}
@@ -73,8 +112,9 @@
label > input: убираем вертикальные
отступы формы и задаём компактную ширину полей (переопределение размеров,
- стили кита остаются) */
+ стили кита остаются). Ширина — с запасом под спиннер: на 4rem он наезжал на
+ цифру в узком сайдбаре */
.duration-fields :deep(.form-group) {
margin: 0;
width: auto;
}
.duration-fields :deep(input) {
- width: 4rem;
+ width: 5rem;
padding: 4px 10px;
+ /* цифры в столбик: «10 ч 5 мин» не дёргается при наборе */
+ font-variant-numeric: tabular-nums;
}
.unit {
color: var(--text-muted, #888);
font-size: 0.9em;
}
-
\ No newline at end of file
+
diff --git a/frontend/src/components/InlineField.vue b/frontend/src/components/InlineField.vue
index f3b4dbb..066ec75 100644
--- a/frontend/src/components/InlineField.vue
+++ b/frontend/src/components/InlineField.vue
@@ -1,5 +1,5 @@
-
+
diff --git a/frontend/src/views/TaskView.vue b/frontend/src/views/TaskView.vue
index a3a5c8a..8d3748c 100644
--- a/frontend/src/views/TaskView.vue
+++ b/frontend/src/views/TaskView.vue
@@ -1140,7 +1140,9 @@
-
+
+
diff --git a/tools/rasterize_icons.sh b/tools/rasterize_icons.sh
index cc1d938..9d50907 100755
--- a/tools/rasterize_icons.sh
+++ b/tools/rasterize_icons.sh
@@ -2,7 +2,9 @@
# Иконки gntodo растрируются из единственного источника — frontend/public/logo.svg
# (знак «стек входящих» на холсте 64×64 со скруглёнными краями, приём gnexus-creds).
#
-# frontend/public/icons/icon-192.png, icon-512.png purpose "any"
+# frontend/public/icons/icon-192.png, icon-512.png purpose "any" — они же
+# иконка системного уведомления (sw.ts)
+# frontend/public/icons/apple-touch-icon.png «на экран Домой» в iOS
# frontend/public/icons/maskable-512.png purpose "maskable"
# extension/public/icons/icon-{16,32,48,128}.png иконки расширения
#
@@ -11,8 +13,13 @@
# сборку ZIP): копия обновляется этим же скриптом, чтобы не отстать от лого.
#
# Нужен ImageMagick с rsvg (проверка: magick -list format | grep SVG → RSVG).
-# Фон #16161E впечатываем в PNG: прозрачность iOS рисует чёрным (углы холста
-# скруглены, за ними — ничего), а maskable на Android обрезается по кругу.
+#
+# Углы. Скругление логотипа (rx 10 = 15% стороны) у иконок "any" остаётся
+# прозрачным: впечатанный фон сравнялся бы с заливкой холста, скругление стало бы
+# невидимым, и иконка читалась бы квадратом с острыми углами — и в шторке
+# уведомлений, и у установленного приложения. Там, где прозрачность нельзя, фон
+# впечатываем: iOS рисует её чёрным (apple-touch-icon), а maskable на Android
+# обрезается по кругу — ему нужен непрозрачный кадр, холст в safe zone (80%).
# После правки логотипа: ./tools/rasterize_icons.sh
set -euo pipefail
cd "$(dirname "$0")/.."
@@ -20,8 +27,15 @@
LOGO=frontend/public/logo.svg
PAGE='#16161E' # фон страницы кита — тот же, что у холста логотипа
SAFE=80 # maskable: холст = 80% кадра (safe zone адаптивных иконок Android)
+APPLE=180 # apple-touch-icon: рекомендованный iOS размер
-raster() { # raster <итоговый размер> <файл> [размер холста внутри кадра]
+raster_rounded() { # raster_rounded <размер> <файл> — скругление источника, углы прозрачны
+ local size=$1 out=$2
+ magick -background none -density $((96 * size / 64)) "$LOGO" \
+ -resize "${size}x${size}" -depth 8 -strip "$out"
+}
+
+raster_opaque() { # raster_opaque <итоговый размер> <файл> [размер холста внутри кадра]
local size=$1 out=$2 canvas=${3:-$1}
magick -background "$PAGE" -density $((96 * canvas / 64)) "$LOGO" \
-resize "${canvas}x${canvas}" -gravity center -extent "${size}x${size}" \
@@ -29,10 +43,11 @@
-define png:color-type=2 "$out" # truecolor без альфы — одинаково у всех размеров
}
-raster 192 frontend/public/icons/icon-192.png
-raster 512 frontend/public/icons/icon-512.png
-raster 512 frontend/public/icons/maskable-512.png $((512 * SAFE / 100))
-for s in 16 32 48 128; do raster "$s" "extension/public/icons/icon-$s.png"; done
+raster_rounded 192 frontend/public/icons/icon-192.png
+raster_rounded 512 frontend/public/icons/icon-512.png
+raster_opaque "$APPLE" frontend/public/icons/apple-touch-icon.png
+raster_opaque 512 frontend/public/icons/maskable-512.png $((512 * SAFE / 100))
+for s in 16 32 48 128; do raster_opaque "$s" "extension/public/icons/icon-$s.png"; done
# лого попапа расширения — копия источника (см. шапку скрипта)
cp "$LOGO" extension/public/logo.svg