feat: photo quality improvements

- webcam capture resolution/quality configurable in admin settings (defaults 640x480 / 0.92)
- enhance photo modal in journal: original vs preview with sliders (brightness, contrast, saturation, sharpen) and auto-levels button
- new endpoint PUT /api/entries/:id/photo/enhance replaces photo, cleans old file and thumb
- sharper HEIC conversion (0.92) and webp thumbnails (85)
- worker: fail explicitly on empty AI response
This commit is contained in:
dev
2026-09-17 15:07:43 +03:00
parent 57e48a9d4f
commit 049df61e55
7 changed files with 354 additions and 11 deletions
+32
View File
@@ -161,6 +161,38 @@
</div>
</div>
<div class="modal-overlay" id="enhanceModal">
<div class="edit-modal" style="max-width:960px">
<h3>Улучшение фотографии</h3>
<div style="display:flex;gap:16px;flex-wrap:wrap">
<div style="flex:1;min-width:280px">
<div style="font-size:.8rem;color:var(--muted);margin-bottom:6px">Оригинал</div>
<div style="background:var(--bg);border:1px solid var(--border);border-radius:8px;overflow:hidden;min-height:120px;display:flex;align-items:center;justify-content:center">
<img id="enhanceOrig" style="max-width:100%;max-height:320px;display:block">
</div>
</div>
<div style="flex:1;min-width:280px">
<div style="font-size:.8rem;color:var(--muted);margin-bottom:6px">Результат</div>
<div style="background:var(--bg);border:1px solid var(--border);border-radius:8px;overflow:hidden;min-height:120px;display:flex;align-items:center;justify-content:center">
<canvas id="enhanceCanvas" style="max-width:100%;max-height:320px;display:none"></canvas>
<span id="enhanceLoading" style="color:var(--muted);font-size:.8rem;padding:24px">Загрузка...</span>
</div>
</div>
</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;margin-top:14px">
<div class="settings-field"><label>Яркость <span id="enhanceBrightnessVal">100%</span></label><input type="range" id="enhanceBrightness" min="50" max="150" value="100"></div>
<div class="settings-field"><label>Контраст <span id="enhanceContrastVal">100%</span></label><input type="range" id="enhanceContrast" min="50" max="150" value="100"></div>
<div class="settings-field"><label>Насыщенность <span id="enhanceSaturateVal">100%</span></label><input type="range" id="enhanceSaturate" min="0" max="200" value="100"></div>
<div class="settings-field"><label>Резкость <span id="enhanceSharpVal">0%</span></label><input type="range" id="enhanceSharp" min="0" max="100" value="0"></div>
</div>
<div class="card-foot" style="justify-content:flex-end;gap:8px;margin-top:6px">
<button type="button" class="btn-primary ghost" id="enhanceAutoBtn" title="Подобрать настройки автоматически">✨ Авто</button>
<button type="button" class="btn-primary ghost" id="enhanceCancelBtn">Оставить как есть</button>
<button type="button" class="btn-primary" id="enhanceSaveBtn">Применить</button>
</div>
</div>
</div>
<div class="toast" id="toast"></div>
<script src="vendor/lucide.min.js"></script>
<script src="admin.js"></script>