massive frontend refactoring (works good)

This commit is contained in:
2026-09-30 01:54:17 +03:00
parent 9203884f53
commit 93ca76c6e1
36 changed files with 1608 additions and 2069 deletions
+169
View File
@@ -0,0 +1,169 @@
import { state } from '../state.js';
import { renderExercise } from './exercise-card.js';
import { renderCardioItem } from './cardio-card.js';
import { formatDate } from '../utils.js';
export function renderWorkoutCard(w) {
const isActive = !w.endTime;
const isExpanded = state.expandedWorkoutId === w.id;
const isReadOnly = w.synced && w.endTime;
const div = document.createElement('div');
div.className = 'workout-accordion';
const headerClass = `workout-header ${isActive ? 'active' : 'completed'}`;
const dateStr = formatDate(w.startTime);
const typeStr = w.type || 'тип не выбран';
const exCount = w.exercises.length;
const cardioCount = w.cardio.length;
let statusBadge;
if (isReadOnly) statusBadge = '<span class="workout-badge synced-badge">✓ архив</span>';
else if (w.synced) statusBadge = '<span class="workout-badge synced-badge">✓</span>';
else statusBadge = '<span class="workout-badge dirty">● не сохранено</span>';
const editDateBtn = !isReadOnly
? `<span class="editable-date" onclick="event.stopPropagation(); WL.editWorkoutDate('${w.id}')">
<span class="edit-icon">✎</span>
</span>`
: '';
div.innerHTML = `
<div class="${headerClass}" onclick="WL.toggleWorkout('${w.id}')">
<div>
<div style="font-weight:600;">${isActive ? '🔥 Тренировка' : '✅ Завершена'}</div>
<div class="workout-meta">${dateStr} ${editDateBtn} • ${typeStr}</div>
<div class="workout-meta">Упр: ${exCount} • Кардио: ${cardioCount}</div>
</div>
<div>${statusBadge} <span class="chevron ${isExpanded ? 'open' : ''}">›</span></div>
</div>
`;
const body = document.createElement('div');
body.className = `workout-body ${isExpanded ? 'expanded' : ''}`;
if (isExpanded) {
body.appendChild(renderWorkoutDetails(w));
}
div.appendChild(body);
return div;
}
export function renderWorkoutDetails(w) {
const wrap = document.createElement('div');
const isActive = !w.endTime;
const isReadOnly = w.synced && w.endTime;
if (isReadOnly) {
const banner = document.createElement('div');
banner.className = 'read-only-banner';
banner.textContent = '🔒 Тренировка в архиве — только просмотр';
wrap.appendChild(banner);
}
// Тип тренировки
const typeCard = document.createElement('div');
typeCard.className = 'card';
if (isReadOnly) {
typeCard.innerHTML = `
<div class="field-group" style="margin:0;">
<span class="text-muted text-small">Тип тренировки</span>
<div style="font-weight:600; margin-top:4px;">${w.type || '—'}</div>
</div>`;
} else {
typeCard.innerHTML = `
<label class="field-group" style="margin:0;">
<span>Тип тренировки</span>
<select onchange="App.getWorkout('${w.id}').type = this.value; App.saveAndRender();">
<option value="">— выберите —</option>
<option ${w.type==='грудь-руки'?'selected':''}>грудь-руки</option>
<option ${w.type==='ноги'?'selected':''}>ноги</option>
<option ${w.type==='спина-плечи'?'selected':''}>спина-плечи</option>
<option ${w.type==='круговая'?'selected':''}>круговая</option>
<option ${w.type==='силовая'?'selected':''}>силовая</option>
<option ${w.type==='многоповторная'?'selected':''}>многоповторная</option>
</select>
</label>`;
}
wrap.appendChild(typeCard);
// Кнопки добавления
if (isActive && !isReadOnly) {
const addSection = document.createElement('div');
addSection.className = 'add-section';
addSection.innerHTML = `
<button class="btn btn-secondary" onclick="EL.addExercise('${w.id}')">+ Упражнение</button>
<button class="btn btn-secondary" onclick="CL.addCardio('${w.id}')">+ Кардио</button>
`;
wrap.appendChild(addSection);
}
// Кардио: разминка сверху
const cardioWarmup = w.cardio.filter(c => c.purpose === 'warmup' || c.purpose === 'separate');
const cardioCooldown = w.cardio.filter(c => c.purpose === 'cooldown');
if (cardioWarmup.length > 0) {
const title = document.createElement('h4');
title.style.margin = '16px 0 8px';
title.textContent = '🔥 Разминка / Кардио';
wrap.appendChild(title);
cardioWarmup.forEach(c => wrap.appendChild(renderCardioItem(w.id, c, isReadOnly)));
}
// Упражнения
[...w.exercises].reverse().forEach(ex => {
wrap.appendChild(renderExercise(w, ex, isReadOnly));
});
// Заминка внизу
if (cardioCooldown.length > 0) {
const title = document.createElement('h4');
title.style.margin = '16px 0 8px';
title.textContent = '🧘 Заминка';
wrap.appendChild(title);
cardioCooldown.forEach(c => wrap.appendChild(renderCardioItem(w.id, c, isReadOnly)));
}
// Комментарий
const notesCard = document.createElement('div');
notesCard.className = 'card mt-10';
if (isReadOnly) {
notesCard.innerHTML = `
<div class="field-group" style="margin:0;">
<span class="text-muted text-small">Комментарий</span>
<div style="margin-top:4px; white-space:pre-wrap;">${w.notes || '—'}</div>
</div>`;
} else {
notesCard.innerHTML = `
<label class="field-group" style="margin:0;">
<span>Комментарий к тренировке</span>
<textarea placeholder="Как прошла тренировка...">${w.notes || ''}</textarea>
</label>`;
notesCard.querySelector('textarea').oninput = (e) => {
w.notes = e.target.value;
window.App.saveAndRender();
};
}
wrap.appendChild(notesCard);
// Блок завершения
const finishBlock = document.createElement('div');
finishBlock.className = 'finish-block';
if (isReadOnly) {
finishBlock.innerHTML = `
<h3>🔒 Архив</h3>
<p class="text-muted text-small">Тренировка синхронизирована и завершена. Редактирование недоступно.</p>`;
} else if (isActive) {
finishBlock.innerHTML = `
<h3>Завершение тренировки</h3>
<p class="text-muted text-small">После завершения данные останутся локально до синхронизации</p>
<button class="btn btn-danger" onclick="WL.finishWorkout('${w.id}')">⏹ Закончить тренировку</button>`;
} else {
finishBlock.innerHTML = `
<h3>Тренировка завершена</h3>
<p class="text-muted text-small">До синхронизации можно редактировать</p>
<button class="btn btn-danger" onclick="WL.deleteWorkout('${w.id}')">🗑 Удалить</button>`;
}
wrap.appendChild(finishBlock);
return wrap;
}