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
+185
View File
@@ -0,0 +1,185 @@
import { state, saveState } from '../state.js';
import { showEditExerciseDialog } from '../modals/edit-exercise-modal.js';
export function showSettings() {
const app = document.getElementById('app');
app.innerHTML = '';
const screen = document.createElement('div');
screen.className = 'settings-screen';
screen.innerHTML = `
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px;">
<h2>⚙️ Настройки</h2>
<button class="btn btn-small btn-secondary" onclick="App.backToMain()">← Назад</button>
</div>
<div class="settings-section">
<h3>📋 Справочник упражнений</h3>
<p class="text-muted text-small mb-10">Управляйте списком упражнений и привязывайте их к типам тренировок.</p>
<div class="field-group">
<div style="display:flex; gap:6px;">
<input type="text" id="new-ref-exercise" placeholder="Новое упражнение...">
<select id="new-ref-type" style="width: auto; min-width: 120px;">
<option value="">тип...</option>
<option value="грудь-руки">грудь-руки</option>
<option value="ноги">ноги</option>
<option value="спина-плечи">спина-плечи</option>
<option value="круговая">круговая</option>
<option value="силовая">силовая</option>
<option value="многоповторная">многоповторная</option>
</select>
<button class="btn btn-small" style="width:auto; padding: 0 20px;" onclick="SettingsLogic.addRefExercise()">+</button>
</div>
</div>
<div id="ref-exercises-list"></div>
</div>
<div class="settings-section">
<h3>📏 Замеры тела</h3>
<div id="body-metrics-list"></div>
</div>
<div class="settings-section">
<h3>🗑 Данные</h3>
<button class="btn btn-danger" onclick="SettingsLogic.clearAllData()">Очистить все данные</button>
</div>
`;
app.appendChild(screen);
_renderRefExercises();
_renderBodyMetricsList();
}
export function addRefExercise() {
const input = document.getElementById('new-ref-exercise');
const typeSelect = document.getElementById('new-ref-type');
const name = input.value.trim();
if (!name) return;
const normalizedName = name.trim().toLowerCase();
const exists = state.exerciseRef.find(
e => e.name.trim().toLowerCase() === normalizedName
);
if (!exists) {
state.exerciseRef.push({
id: (state.nextId++).toString(),
name: name.trim(),
workoutType: typeSelect.value,
});
}
saveState();
input.value = '';
typeSelect.value = '';
_renderRefExercises();
}
export function deleteRefExercise(id) {
if (!confirm('Удалить из справочника? (в тренировках останется)')) return;
state.exerciseRef = state.exerciseRef.filter(e => e.id !== id);
saveState();
_renderRefExercises();
}
export function updateRefExerciseType(id, newType) {
const ex = state.exerciseRef.find(e => e.id === id);
if (ex) {
ex.workoutType = newType;
saveState();
}
}
export function editRefExercise(id) {
const ex = state.exerciseRef.find(e => e.id === id);
if (!ex) return;
showEditExerciseDialog(ex, (updatedData) => {
if (!updatedData) return;
Object.assign(ex, updatedData);
saveState();
_renderRefExercises();
});
}
export function clearAllData() {
if (!confirm('Удалить ВСЕ данные? Это действие необратимо!')) return;
if (!confirm('Точно уверены?')) return;
localStorage.clear();
location.reload();
}
export function _renderRefExercises() {
const list = document.getElementById('ref-exercises-list');
if (!list) return;
if (state.exerciseRef.length === 0) {
list.innerHTML = '<p class="text-muted text-small">Справочник пуст</p>';
return;
}
const sorted = [...state.exerciseRef].sort((a, b) => {
if (a.workoutType !== b.workoutType) return (a.workoutType || '').localeCompare(b.workoutType || '');
return a.name.localeCompare(b.name);
});
list.innerHTML = sorted.map(ex => {
let count = 0;
state.workouts.forEach(w => {
w.exercises.forEach(e => {
if (e.name.trim().toLowerCase() === ex.name.trim().toLowerCase()) count++;
});
});
return `
<div class="exercise-ref-item">
<div style="flex:1;">
<span class="name">${ex.name}</span>
<span class="count">(${count}×)</span>
${ex.workoutType ? `<span class="type-badge">${ex.workoutType}</span>` : ''}
</div>
<div style="display:flex; gap:4px; align-items:center;">
<select onchange="SettingsLogic.updateRefExerciseType('${ex.id}', this.value)"
style="width:auto; min-width:100px; padding:6px; font-size:0.8rem;">
<option value="">тип...</option>
<option value="грудь-руки" ${ex.workoutType==='грудь-руки'?'selected':''}>грудь-руки</option>
<option value="ноги" ${ex.workoutType==='ноги'?'selected':''}>ноги</option>
<option value="спина-плечи" ${ex.workoutType==='спина-плечи'?'selected':''}>спина-плечи</option>
<option value="круговая" ${ex.workoutType==='круговая'?'selected':''}>круговая</option>
<option value="силовая" ${ex.workoutType==='силовая'?'selected':''}>силовая</option>
<option value="многоповторная" ${ex.workoutType==='многоповторная'?'selected':''}>многоповторная</option>
</select>
<button class="icon-btn" onclick="SettingsLogic.editRefExercise('${ex.id}')">✎</button>
<button class="icon-btn danger" onclick="SettingsLogic.deleteRefExercise('${ex.id}')">✕</button>
</div>
</div>
`;
}).join('');
}
export function _renderBodyMetricsList() {
const list = document.getElementById('body-metrics-list');
if (!list) return;
if (state.bodyMetrics.length === 0) {
list.innerHTML = '<p class="text-muted text-small">Нет замеров</p>';
return;
}
list.innerHTML = state.bodyMetrics.map(m => {
const date = new Date(m.date);
const dateStr = date.toLocaleDateString('ru-RU') + ' ' + date.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' });
const parts = [];
if (m.weight) parts.push(`⚖️ ${m.weight} кг`);
if (m.chest) parts.push(`📏 ${m.chest} см`);
if (m.waist) parts.push(`📏 ${m.waist} см`);
if (m.hips) parts.push(`📏 ${m.hips} см`);
if (m.arms) parts.push(`💪 ${m.arms} см`);
if (m.legs) parts.push(`🦵 ${m.legs} см`);
return `
<div class="exercise-ref-item">
<div>
<div style="font-weight:500;">${dateStr}</div>
<div class="text-small text-muted">${parts.join(' • ') || '—'}</div>
</div>
<div style="display:flex; gap:4px;">
<button class="icon-btn" onclick="ML.editBodyMetric('${m.id}')">✎</button>
<button class="icon-btn danger" onclick="ML.deleteMetric('${m.id}')">✕</button>
</div>
</div>
`;
}).join('');
}
window.SettingsLogic = {
show: showSettings,
addRefExercise, deleteRefExercise, updateRefExerciseType,
editRefExercise, clearAllData,
_renderRefExercises, _renderBodyMetricsList,
};