1555 lines
63 KiB
HTML
1555 lines
63 KiB
HTML
<!doctype html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Мои тренировки — Мадина</title>
|
||
<style>
|
||
* { margin: 0; box-sizing: border-box; }
|
||
body {
|
||
font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
min-height: 100vh;
|
||
color: #333;
|
||
}
|
||
.container { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||
header {
|
||
text-align: center;
|
||
padding: 40px 20px;
|
||
color: white;
|
||
}
|
||
header h1 { font-size: clamp(28px, 5vw, 42px); margin-bottom: 10px; }
|
||
header p { font-size: 18px; opacity: 0.9; }
|
||
.nav {
|
||
display: flex;
|
||
gap: 10px;
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
margin-bottom: 30px;
|
||
}
|
||
.nav button {
|
||
padding: 12px 24px;
|
||
border: none;
|
||
border-radius: 25px;
|
||
background: rgba(255,255,255,0.2);
|
||
color: white;
|
||
font-size: 16px;
|
||
cursor: pointer;
|
||
transition: 0.3s;
|
||
}
|
||
.nav button.active, .nav button:hover {
|
||
background: white;
|
||
color: #667eea;
|
||
}
|
||
.section {
|
||
background: white;
|
||
border-radius: 20px;
|
||
padding: 30px;
|
||
margin-bottom: 30px;
|
||
box-shadow: 0 10px 40px rgba(0,0,0,0.1);
|
||
display: none;
|
||
}
|
||
.section.active { display: block; }
|
||
h2 { color: #667eea; margin-bottom: 20px; font-size: 26px; }
|
||
h3 { color: #764ba2; margin: 20px 0 15px; font-size: 20px; }
|
||
|
||
/* Workout of the day */
|
||
.workout-card {
|
||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||
border-radius: 15px;
|
||
padding: 25px;
|
||
margin-bottom: 20px;
|
||
}
|
||
.workout-card h3 { margin-top: 0; color: #333; }
|
||
.exercise {
|
||
background: white;
|
||
border-radius: 12px;
|
||
padding: 20px;
|
||
margin: 15px 0;
|
||
box-shadow: 0 4px 15px rgba(0,0,0,0.08);
|
||
}
|
||
.exercise h4 { color: #667eea; margin-bottom: 10px; }
|
||
.exercise-meta {
|
||
display: flex;
|
||
gap: 15px;
|
||
flex-wrap: wrap;
|
||
margin: 10px 0;
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
.exercise-meta span {
|
||
background: #f0f0f5;
|
||
padding: 5px 12px;
|
||
border-radius: 15px;
|
||
}
|
||
.video-placeholder {
|
||
width: 100%;
|
||
aspect-ratio: 16/9;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
border-radius: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: white;
|
||
font-size: 18px;
|
||
margin: 15px 0;
|
||
cursor: pointer;
|
||
transition: transform 0.3s;
|
||
}
|
||
.video-placeholder:hover { transform: scale(1.02); }
|
||
.video-placeholder::before {
|
||
content: "▶";
|
||
font-size: 48px;
|
||
margin-right: 15px;
|
||
}
|
||
|
||
/* Exercise catalog */
|
||
.exercise-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||
gap: 20px;
|
||
}
|
||
.exercise-card {
|
||
background: white;
|
||
border-radius: 15px;
|
||
overflow: hidden;
|
||
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
|
||
transition: transform 0.3s;
|
||
}
|
||
.exercise-card:hover { transform: translateY(-5px); }
|
||
.exercise-card .video {
|
||
width: 100%;
|
||
aspect-ratio: 16/9;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: white;
|
||
font-size: 36px;
|
||
cursor: pointer;
|
||
}
|
||
.exercise-card .info { padding: 20px; }
|
||
.exercise-card .info h4 { color: #667eea; margin-bottom: 10px; }
|
||
.exercise-card .info p { color: #666; font-size: 14px; line-height: 1.6; }
|
||
.exercise-card .meta {
|
||
display: flex;
|
||
gap: 10px;
|
||
margin-top: 15px;
|
||
flex-wrap: wrap;
|
||
}
|
||
.exercise-card .meta span {
|
||
background: #f0f0f5;
|
||
padding: 5px 12px;
|
||
border-radius: 15px;
|
||
font-size: 12px;
|
||
color: #666;
|
||
}
|
||
|
||
/* Calendar */
|
||
.calendar-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(7, 1fr);
|
||
gap: 10px;
|
||
}
|
||
.calendar-day {
|
||
background: #f8f9fc;
|
||
border-radius: 10px;
|
||
padding: 15px 10px;
|
||
text-align: center;
|
||
min-height: 100px;
|
||
cursor: pointer;
|
||
transition: 0.3s;
|
||
border: 2px solid transparent;
|
||
}
|
||
.calendar-day:hover { border-color: #667eea; }
|
||
.calendar-day.today {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
}
|
||
.calendar-day.done {
|
||
background: #d4edda;
|
||
border-color: #28a745;
|
||
}
|
||
.calendar-day .day-num {
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
margin-bottom: 5px;
|
||
}
|
||
.calendar-day .workout-type {
|
||
font-size: 11px;
|
||
line-height: 1.4;
|
||
}
|
||
.calendar-header {
|
||
display: grid;
|
||
grid-template-columns: repeat(7, 1fr);
|
||
gap: 10px;
|
||
margin-bottom: 10px;
|
||
}
|
||
.calendar-header div {
|
||
text-align: center;
|
||
font-weight: bold;
|
||
color: #667eea;
|
||
padding: 10px;
|
||
}
|
||
|
||
/* Tracker */
|
||
.tracker-form {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
gap: 20px;
|
||
margin-bottom: 30px;
|
||
}
|
||
.tracker-form input {
|
||
padding: 15px;
|
||
border: 2px solid #e0e0e5;
|
||
border-radius: 12px;
|
||
font-size: 16px;
|
||
}
|
||
.tracker-form input:focus {
|
||
border-color: #667eea;
|
||
outline: none;
|
||
}
|
||
.btn {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
border: none;
|
||
padding: 15px 30px;
|
||
border-radius: 12px;
|
||
font-size: 16px;
|
||
cursor: pointer;
|
||
transition: 0.3s;
|
||
}
|
||
.btn:hover { transform: translateY(-2px); box-shadow: 0 5px 20px rgba(102,126,234,0.4); }
|
||
.btn-block { width: 100%; }
|
||
|
||
.progress-stats {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||
gap: 20px;
|
||
margin-top: 30px;
|
||
}
|
||
.stat-card {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
padding: 25px;
|
||
border-radius: 15px;
|
||
text-align: center;
|
||
}
|
||
.stat-card .value { font-size: 36px; font-weight: bold; }
|
||
.stat-card .label { opacity: 0.9; margin-top: 5px; }
|
||
|
||
.week-selector {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
}
|
||
.week-selector button {
|
||
background: #667eea;
|
||
color: white;
|
||
border: none;
|
||
padding: 10px 20px;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.category-filter {
|
||
display: flex;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
margin-bottom: 20px;
|
||
}
|
||
.category-filter button {
|
||
padding: 8px 16px;
|
||
border: 2px solid #667eea;
|
||
background: white;
|
||
color: #667eea;
|
||
border-radius: 20px;
|
||
cursor: pointer;
|
||
}
|
||
.category-filter button.active {
|
||
background: #667eea;
|
||
color: white;
|
||
}
|
||
|
||
.modal {
|
||
display: none;
|
||
position: fixed;
|
||
top: 0; left: 0;
|
||
width: 100%; height: 100%;
|
||
background: rgba(0,0,0,0.8);
|
||
z-index: 1000;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.modal.active { display: flex; }
|
||
.modal-content {
|
||
background: white;
|
||
border-radius: 20px;
|
||
padding: 30px;
|
||
max-width: 800px;
|
||
width: 90%;
|
||
max-height: 90vh;
|
||
overflow-y: auto;
|
||
}
|
||
.modal-close {
|
||
float: right;
|
||
font-size: 28px;
|
||
cursor: pointer;
|
||
color: #666;
|
||
}
|
||
|
||
.goal-info {
|
||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||
border-radius: 15px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
.goal-info p { margin: 5px 0; }
|
||
|
||
/* Музыкальный плеер */
|
||
.music-player {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
border-radius: 15px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
color: white;
|
||
}
|
||
.music-player h3 { margin: 0 0 15px; font-size: 18px; }
|
||
.player-controls {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 15px;
|
||
flex-wrap: wrap;
|
||
}
|
||
.player-btn {
|
||
width: 50px;
|
||
height: 50px;
|
||
border-radius: 50%;
|
||
border: none;
|
||
background: white;
|
||
color: #667eea;
|
||
font-size: 20px;
|
||
cursor: pointer;
|
||
transition: 0.3s;
|
||
}
|
||
.player-btn:hover { transform: scale(1.1); }
|
||
.player-btn.big {
|
||
width: 60px;
|
||
height: 60px;
|
||
font-size: 28px;
|
||
}
|
||
.playlist-select {
|
||
flex: 1;
|
||
min-width: 200px;
|
||
padding: 12px;
|
||
border-radius: 10px;
|
||
border: none;
|
||
font-size: 14px;
|
||
background: rgba(255,255,255,0.9);
|
||
color: #333;
|
||
}
|
||
.now-playing {
|
||
margin-top: 15px;
|
||
font-size: 14px;
|
||
opacity: 0.9;
|
||
}
|
||
.volume-control {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
margin-top: 10px;
|
||
}
|
||
.volume-control input {
|
||
flex: 1;
|
||
height: 6px;
|
||
-webkit-appearance: none;
|
||
background: rgba(255,255,255,0.3);
|
||
border-radius: 3px;
|
||
}
|
||
.volume-control input::-webkit-slider-thumb {
|
||
-webkit-appearance: none;
|
||
width: 18px;
|
||
height: 18px;
|
||
border-radius: 50%;
|
||
background: white;
|
||
cursor: pointer;
|
||
}
|
||
.equalizer {
|
||
display: flex;
|
||
gap: 3px;
|
||
align-items: flex-end;
|
||
height: 20px;
|
||
margin-left: auto;
|
||
}
|
||
.equalizer span {
|
||
width: 4px;
|
||
background: rgba(255,255,255,0.7);
|
||
border-radius: 2px;
|
||
animation: equalize 0.5s ease-in-out infinite alternate;
|
||
}
|
||
.equalizer span:nth-child(2) { animation-delay: 0.1s; }
|
||
.equalizer span:nth-child(3) { animation-delay: 0.2s; }
|
||
.equalizer span:nth-child(4) { animation-delay: 0.3s; }
|
||
@keyframes equalize {
|
||
from { height: 5px; }
|
||
to { height: 20px; }
|
||
}
|
||
.equalizer.off span { animation: none; height: 5px; }
|
||
|
||
/* Моя музыка */
|
||
.my-music {
|
||
margin-top: 20px;
|
||
background: rgba(255,255,255,0.1);
|
||
border-radius: 12px;
|
||
padding: 20px;
|
||
}
|
||
.my-music h4 { margin: 0 0 15px; font-size: 16px; }
|
||
.add-music-form {
|
||
display: flex;
|
||
gap: 10px;
|
||
margin-bottom: 15px;
|
||
flex-wrap: wrap;
|
||
}
|
||
.add-music-form input {
|
||
flex: 1;
|
||
min-width: 200px;
|
||
padding: 12px;
|
||
border-radius: 8px;
|
||
border: none;
|
||
font-size: 14px;
|
||
}
|
||
.add-music-form button {
|
||
padding: 12px 24px;
|
||
background: white;
|
||
color: #667eea;
|
||
border: none;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
font-weight: bold;
|
||
}
|
||
.my-playlist {
|
||
max-height: 300px;
|
||
overflow-y: auto;
|
||
}
|
||
.playlist-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 10px;
|
||
background: rgba(255,255,255,0.1);
|
||
border-radius: 8px;
|
||
margin: 8px 0;
|
||
cursor: pointer;
|
||
transition: 0.2s;
|
||
}
|
||
.playlist-item:hover { background: rgba(255,255,255,0.2); }
|
||
.playlist-item.active { background: rgba(255,255,255,0.3); }
|
||
.playlist-item .remove {
|
||
margin-left: auto;
|
||
opacity: 0.7;
|
||
cursor: pointer;
|
||
font-size: 18px;
|
||
}
|
||
.playlist-item .remove:hover { opacity: 1; }
|
||
.music-type {
|
||
font-size: 12px;
|
||
padding: 3px 8px;
|
||
border-radius: 4px;
|
||
background: rgba(255,255,255,0.2);
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<header>
|
||
<h1>💪 Мои тренировки</h1>
|
||
<p>Персональная программа на 8 недель</p>
|
||
</header>
|
||
|
||
<nav class="nav">
|
||
<button class="active" onclick="showSection('today')">📅 Сегодня</button>
|
||
<button onclick="showSection('catalog')">🎬 Каталог упражнений</button>
|
||
<button onclick="showSection('calendar')">📆 Календарь</button>
|
||
<button onclick="showSection('tracker')">📊 Трекер прогресса</button>
|
||
<button onclick="showSection('nutrition')">🥗 Питание</button>
|
||
<button onclick="showSection('habits')">✨ Привычки</button>
|
||
</nav>
|
||
|
||
<!-- СЕКЦИЯ: СЕГОДНЯ -->
|
||
<div id="today" class="section active">
|
||
<h2>Тренировка на сегодня</h2>
|
||
|
||
<!-- Музыкальный плеер -->
|
||
<div class="music-player">
|
||
<h3>🎵 Мотивационная музыка</h3>
|
||
<div class="player-controls">
|
||
<button class="player-btn" onclick="prevTrack()">⏮</button>
|
||
<button class="player-btn big" onclick="togglePlay()" id="play-btn">▶</button>
|
||
<button class="player-btn" onclick="nextTrack()">⏭</button>
|
||
<select class="playlist-select" id="playlist-select" onchange="changePlaylist()">
|
||
<option value="workout">💪 Для тренировки (энергичная)</option>
|
||
<option value="cardio">🏃 Для кардио (быстрая)</option>
|
||
<option value="yoga">🧘 Для растяжки (спокойная)</option>
|
||
<option value="motivation">🔥 Мотивация (речь + музыка)</option>
|
||
</select>
|
||
<div class="equalizer off" id="equalizer">
|
||
<span></span><span></span><span></span><span></span>
|
||
</div>
|
||
</div>
|
||
<div class="volume-control">
|
||
<span>🔈</span>
|
||
<input type="range" min="0" max="100" value="70" oninput="setVolume(this.value)">
|
||
<span>🔊</span>
|
||
</div>
|
||
<div class="now-playing" id="now-playing">Выберите плейлист и нажмите ▶</div>
|
||
|
||
<!-- Моя музыка -->
|
||
<div class="my-music">
|
||
<h4>🎵 Моя музыка</h4>
|
||
<div class="add-music-form">
|
||
<input type="text" id="music-url" placeholder="YouTube ссылка (https://youtube.com/watch?v=...)">
|
||
<input type="text" id="music-name" placeholder="Название песни/аудиокниги">
|
||
<select id="music-type" style="padding:12px; border-radius:8px; border:none;">
|
||
<option value="song">Песня</option>
|
||
<option value="audiobook">Аудиокнига</option>
|
||
<option value="motivation">Мотивация</option>
|
||
</select>
|
||
<button onclick="addMyMusic()">+ Добавить</button>
|
||
</div>
|
||
<div class="my-playlist" id="my-playlist"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="goal-info">
|
||
<p><strong>Цель:</strong> Похудение, осанка, укрепление рук</p>
|
||
<p><strong>Длительность:</strong> 45-60 минут</p>
|
||
<p><strong>Фокус:</strong> <span id="today-focus">Пресс и осанка</span></p>
|
||
</div>
|
||
<div id="today-workout"></div>
|
||
<button class="btn btn-block" onclick="markTodayDone()">✅ Отметить тренировку выполненной</button>
|
||
</div>
|
||
|
||
<!-- СЕКЦИЯ: КАТАЛОГ -->
|
||
<div id="catalog" class="section">
|
||
<h2>Каталог упражнений с видео</h2>
|
||
<div class="category-filter">
|
||
<button class="active" onclick="filterCatalog('all')">Все</button>
|
||
<button onclick="filterCatalog('posture')">Осанка и спина</button>
|
||
<button onclick="filterCatalog('abs')">Живот и бока</button>
|
||
<button onclick="filterCatalog('arms')">Руки</button>
|
||
<button onclick="filterCatalog('legs')">Ноги и ягодицы</button>
|
||
<button onclick="filterCatalog('cardio')">Кардио</button>
|
||
</div>
|
||
<div class="exercise-grid" id="exercise-grid"></div>
|
||
</div>
|
||
|
||
<!-- СЕКЦИЯ: КАЛЕНДАРЬ -->
|
||
<div id="calendar" class="section">
|
||
<h2>Календарь тренировок на 8 недель</h2>
|
||
<div class="week-selector">
|
||
<button onclick="changeWeek(-1)">← Назад</button>
|
||
<span id="week-label">Неделя 1</span>
|
||
<button onclick="changeWeek(1)">Вперёд →</button>
|
||
</div>
|
||
<div class="calendar-header">
|
||
<div>Пн</div><div>Вт</div><div>Ср</div><div>Чт</div><div>Пт</div><div>Сб</div><div>Вс</div>
|
||
</div>
|
||
<div class="calendar-grid" id="calendar-grid"></div>
|
||
</div>
|
||
|
||
<!-- СЕКЦИЯ: ТРЕКЕР -->
|
||
<div id="tracker" class="section">
|
||
<h2>Трекер прогресса</h2>
|
||
<div class="tracker-form">
|
||
<input type="number" id="weight" placeholder="Вес (кг)" step="0.1">
|
||
<input type="number" id="waist" placeholder="Талия (см)">
|
||
<input type="number" id="hips" placeholder="Бёдра (см)">
|
||
<input type="number" id="arms" placeholder="Руки (см)">
|
||
<button class="btn" onclick="addProgress()">Записать</button>
|
||
</div>
|
||
<div class="progress-stats" id="progress-stats"></div>
|
||
|
||
<!-- График веса -->
|
||
<div style="margin-top: 30px; background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); border-radius: 15px; padding: 25px;">
|
||
<h3>📈 График веса</h3>
|
||
<p style="margin-bottom: 15px; color: #666;">Цель: <strong>58 кг</strong> через 8 недель</p>
|
||
<canvas id="weight-chart" height="80" style="width: 100%; background: white; border-radius: 10px;"></canvas>
|
||
<div style="display: flex; justify-content: space-between; margin-top: 10px; font-size: 12px; color: #666;">
|
||
<span>Неделя 1</span>
|
||
<span>Неделя 4</span>
|
||
<span>Неделя 8</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="progress-history" style="margin-top: 30px;"></div>
|
||
</div>
|
||
|
||
<!-- СЕКЦИЯ: ПРИВЫЧКИ -->
|
||
<div id="habits" class="section">
|
||
<h2>✨ Полезные привычки для похудения</h2>
|
||
<p style="margin-bottom: 20px; color: #666;">Отмечай галочкой каждый день, когда выполнил привычку. Цель — 21 день подряд!</p>
|
||
|
||
<div id="habits-list"></div>
|
||
|
||
<div class="progress-stats" style="margin-top: 30px;">
|
||
<div class="stat-card" style="background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);">
|
||
<div class="value" id="habits-streak">0</div>
|
||
<div class="label">Дней подряд</div>
|
||
</div>
|
||
<div class="stat-card" style="background: linear-gradient(135deg, #30cfd0 0%, #330867 100%);">
|
||
<div class="value" id="habits-total">0</div>
|
||
<div class="label">Всего выполнено</div>
|
||
</div>
|
||
<div class="stat-card" style="background: linear-gradient(135deg, #a8ff78 0%, #78ffd6 100%);">
|
||
<div class="value" id="habits-percent">0%</div>
|
||
<div class="label">Успех сегодня</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- СЕКЦИЯ: ПИТАНИЕ -->
|
||
<div id="nutrition" class="section">
|
||
<h2>🥗 Питание для похудения</h2>
|
||
|
||
<div class="goal-info" style="background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);">
|
||
<h3 style="margin-top: 0; color: #333;">Твоя цель</h3>
|
||
<p><strong>Стартовый вес:</strong> 65 кг</p>
|
||
<p><strong>Цель за 2 месяца:</strong> 58-59 кг (-6-7 кг)</p>
|
||
<p><strong>Калорий в день:</strong> 1400-1500 ккал</p>
|
||
<p><strong>Воды в день:</strong> 2-2.5 литра</p>
|
||
</div>
|
||
|
||
<h3>📋 Рекомендации по питанию</h3>
|
||
<div class="exercise-grid" style="grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));">
|
||
<div class="exercise-card">
|
||
<div class="info">
|
||
<h4>🍳 Завтрак (7:00-9:00)</h4>
|
||
<p>Омлет из 2 яиц с овощами + кусочек цельнозернового хлеба</p>
|
||
<p>Или: овсянка на воде с ягодами + 1 яйцо</p>
|
||
<div class="meta"><span>~350 ккал</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="exercise-card">
|
||
<div class="info">
|
||
<h4>🥗 Перекус (11:00)</h4>
|
||
<p>Яблоко/груша + 10 орешков (миндаль/грецкий)</p>
|
||
<p>Или: натуральный йогурт без сахара</p>
|
||
<div class="meta"><span>~150 ккал</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="exercise-card">
|
||
<div class="info">
|
||
<h4>🍲 Обед (13:00-14:00)</h4>
|
||
<p>Куриная грудка/рыба (150г) + гречка/рис (100г) + салат</p>
|
||
<p>Или: суп на овощном бульоне + кусочек мяса</p>
|
||
<div class="meta"><span>~450 ккал</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="exercise-card">
|
||
<div class="info">
|
||
<h4>🥛 Перекус (16:00)</h4>
|
||
<p>Творог (100г) + ложка мёда</p>
|
||
<p>Или: кефир + 1 хлебец</p>
|
||
<div class="meta"><span>~150 ккал</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="exercise-card">
|
||
<div class="info">
|
||
<h4>🐟 Ужин (18:00-19:00)</h4>
|
||
<p>Рыба/курица (120г) + тушёные овощи</p>
|
||
<p>Или: салат с тунцом и яйцом</p>
|
||
<div class="meta"><span>~300 ккал</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="exercise-card">
|
||
<div class="info">
|
||
<h4>⚠️ Что исключить</h4>
|
||
<p>❌ Сахар и сладости</p>
|
||
<p>❌ Белый хлеб и выпечку</p>
|
||
<p>❌ Газировку и пакетированные соки</p>
|
||
<p>❌ Фастфуд и майонез</p>
|
||
<div class="meta"><span>Экономия ~500 ккал/день</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style="margin-top: 30px;">💧 Трекер воды</h3>
|
||
<div style="background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%); border-radius: 15px; padding: 25px; margin-top: 20px;">
|
||
<p style="margin-bottom: 15px;">Выпито сегодня: <strong id="water-count">0</strong> из 8 стаканов</p>
|
||
<div style="display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 15px;" id="water-glasses"></div>
|
||
<button class="btn" onclick="addWater()">💧 Выпить стакан</button>
|
||
<button class="btn" onclick="resetWater()" style="background: #999; margin-left: 10px;">Сбросить</button>
|
||
</div>
|
||
|
||
<h3 style="margin-top: 30px;">📊 Калькулятор калорий</h3>
|
||
<div style="background: #f8f9fc; border-radius: 15px; padding: 25px; margin-top: 20px;">
|
||
<p>Рассчитай калорийность продуктов, которые ешь:</p>
|
||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin-top: 15px;">
|
||
<input type="text" id="product-name" placeholder="Продукт (например: яблоко)" style="padding: 12px; border: 2px solid #e0e0e5; border-radius: 10px;">
|
||
<input type="number" id="product-grams" placeholder="Вес (грамм)" style="padding: 12px; border: 2px solid #e0e0e5; border-radius: 10px;">
|
||
</div>
|
||
<button class="btn" onclick="calculateCalories()" style="margin-top: 15px;">Рассчитать</button>
|
||
<div id="calories-result" style="margin-top: 15px; font-size: 18px; font-weight: bold; color: #667eea;"></div>
|
||
</div>
|
||
|
||
<div class="progress-stats" style="margin-top: 30px;">
|
||
<div class="stat-card" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);">
|
||
<div class="value" id="total-water">0</div>
|
||
<div class="label">Стаканов всего</div>
|
||
</div>
|
||
<div class="stat-card" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
|
||
<div class="value" id="days-tracked">0</div>
|
||
<div class="label">Дней отслеживания</div>
|
||
</div>
|
||
<div class="stat-card" style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);">
|
||
<div class="value" id="avg-weight">65</div>
|
||
<div class="label">Средний вес</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Модальное окно для видео -->
|
||
<div class="modal" id="video-modal">
|
||
<div class="modal-content">
|
||
<span class="modal-close" onclick="closeModal()">×</span>
|
||
<h3 id="modal-title"></h3>
|
||
<div id="modal-video"></div>
|
||
<p id="modal-desc" style="margin-top: 20px; line-height: 1.6;"></p>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// === МУЗЫКАЛЬНЫЙ ПЛЕЕР ===
|
||
const playlists = {
|
||
workout: [
|
||
{ name: "Eye of the Tiger - Survivor", url: "https://www.youtube.com/embed/btPJPFnesV4?autoplay=1&loop=1&playlist=btPJPFnesV4" },
|
||
{ name: "Stronger - Kanye West", url: "https://www.youtube.com/embed/PsO6ZnU8G6g?autoplay=1&loop=1&playlist=PsO6ZnU8G6g" },
|
||
{ name: "Lose Yourself - Eminem", url: "https://www.youtube.com/embed/_Yhyp-_hX2s?autoplay=1&loop=1&playlist=_Yhyp-_hX2s" },
|
||
{ name: "Titanium - David Guetta", url: "https://www.youtube.com/embed/JRfuAukYTKg?autoplay=1&loop=1&playlist=JRfuAukYTKg" },
|
||
{ name: "Can't Hold Us - Macklemore", url: "https://www.youtube.com/embed/2zNSgSzhBfM?autoplay=1&loop=1&playlist=2zNSgSzhBfM" }
|
||
],
|
||
cardio: [
|
||
{ name: "Uptown Funk - Mark Ronson", url: "https://www.youtube.com/embed/OPf0YbXqDm0?autoplay=1&loop=1&playlist=OPf0YbXqDm0" },
|
||
{ name: "Shake It Off - Taylor Swift", url: "https://www.youtube.com/embed/nfWlot6h_JM?autoplay=1&loop=1&playlist=nfWlot6h_JM" },
|
||
{ name: "Happy - Pharrell Williams", url: "https://www.youtube.com/embed/ZbZSe6N_BXs?autoplay=1&loop=1&playlist=ZbZSe6N_BXs" },
|
||
{ name: "24K Magic - Bruno Mars", url: "https://www.youtube.com/embed/UqyT8IEBkvY?autoplay=1&loop=1&playlist=UqyT8IEBkvY" }
|
||
],
|
||
yoga: [
|
||
{ name: "Weightless - Marconi Union", url: "https://www.youtube.com/embed/UfcAV6ZK8hE?autoplay=1&loop=1&playlist=UfcAV6ZK8hE" },
|
||
{ name: "River Flows in You - Yiruma", url: "https://www.youtube.com/embed/7maJOI3QMu0?autoplay=1&loop=1&playlist=7maJOI3QMu0" },
|
||
{ name: "Meditation Music - Relaxing Piano", url: "https://www.youtube.com/embed/1ZYbU82GVz4?autoplay=1&loop=1&playlist=1ZYbU82GVz4" },
|
||
{ name: "Tibetan Bowls - Healing", url: "https://www.youtube.com/embed/47G2BgXSC74?autoplay=1&loop=1&playlist=47G2BgXSC74" }
|
||
],
|
||
motivation: [
|
||
{ name: "Motivational Speech - Believe", url: "https://www.youtube.com/embed/rHY3HCxJF20?autoplay=1&loop=1&playlist=rHY3HCxJF20" },
|
||
{ name: "Never Give Up - Motivation", url: "https://www.youtube.com/embed/tvnxMyrWb1E?autoplay=1&loop=1&playlist=tvnxMyrWb1E" },
|
||
{ name: "Warrior Mindset - Motivation", url: "https://www.youtube.com/embed/hp3j8c9pKxU?autoplay=1&loop=1&playlist=hp3j8c9pKxU" }
|
||
]
|
||
};
|
||
|
||
// Моя музыка (загружается из localStorage)
|
||
let myMusic = JSON.parse(localStorage.getItem('myMusic') || '[]');
|
||
|
||
let currentPlaylist = 'workout';
|
||
let currentTrackIndex = 0;
|
||
let isPlaying = false;
|
||
let player = null;
|
||
|
||
// Загрузка YouTube IFrame API
|
||
const tag = document.createElement('script');
|
||
tag.src = 'https://www.youtube.com/iframe_api';
|
||
const firstScriptTag = document.getElementsByTagName('script')[0];
|
||
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
|
||
|
||
function onYouTubeIframeAPIReady() {
|
||
console.log('YouTube Player API готов');
|
||
}
|
||
|
||
function initPlayer() {
|
||
if (!player && window.YT && YT.Player) {
|
||
player = new YT.Player('music-player-frame', {
|
||
height: '0',
|
||
width: '0',
|
||
playerVars: { 'autoplay': 0, 'controls': 0 },
|
||
events: {
|
||
'onReady': onPlayerReady,
|
||
'onStateChange': onPlayerStateChange
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
function onPlayerReady(event) {
|
||
console.log('Плеер готов');
|
||
}
|
||
|
||
function onPlayerStateChange(event) {
|
||
if (event.data === YT.PlayerState.ENDED) {
|
||
nextTrack();
|
||
}
|
||
updatePlayButton();
|
||
}
|
||
|
||
function changePlaylist() {
|
||
currentPlaylist = document.getElementById('playlist-select').value;
|
||
currentTrackIndex = 0;
|
||
loadTrack(currentTrackIndex);
|
||
}
|
||
|
||
// === МОЯ МУЗЫКА ===
|
||
function addMyMusic() {
|
||
const url = document.getElementById('music-url').value.trim();
|
||
const name = document.getElementById('music-name').value.trim() || 'Мой трек';
|
||
const type = document.getElementById('music-type').value;
|
||
|
||
if (!url) {
|
||
alert('Вставь ссылку на YouTube');
|
||
return;
|
||
}
|
||
|
||
// Конвертация YouTube ссылки в embed
|
||
let embedUrl = url;
|
||
const videoId = extractVideoId(url);
|
||
if (videoId) {
|
||
embedUrl = 'https://www.youtube.com/embed/' + videoId + '?autoplay=1&loop=1&playlist=' + videoId;
|
||
}
|
||
|
||
myMusic.push({
|
||
id: Date.now(),
|
||
name: name,
|
||
url: embedUrl,
|
||
type: type,
|
||
videoId: videoId
|
||
});
|
||
|
||
localStorage.setItem('myMusic', JSON.stringify(myMusic));
|
||
renderMyPlaylist();
|
||
|
||
document.getElementById('music-url').value = '';
|
||
document.getElementById('music-name').value = '';
|
||
}
|
||
|
||
function extractVideoId(url) {
|
||
const match = url.match(/(?:v=|\/)([a-zA-Z0-9_-]{11})/);
|
||
return match ? match[1] : null;
|
||
}
|
||
|
||
function renderMyPlaylist() {
|
||
const container = document.getElementById('my-playlist');
|
||
if (!container) return;
|
||
|
||
if (myMusic.length === 0) {
|
||
container.innerHTML = '<p style="opacity:0.7; font-size:14px;">Пока нет добавленных треков. Добавь любимую музыку!</p>';
|
||
return;
|
||
}
|
||
|
||
container.innerHTML = myMusic.map(track => {
|
||
const typeLabels = { song: '🎵', audiobook: '📚', motivation: '🔥' };
|
||
const isActive = currentPlaylist === 'my' && currentTrackIndex === myMusic.findIndex(t => t.id === track.id);
|
||
|
||
return '<div class="playlist-item' + (isActive ? ' active' : '') + '" onclick="playMyTrack(' + track.id + ')">' +
|
||
'<span style="font-size:20px;">' + typeLabels[track.type] + '</span>' +
|
||
'<span style="flex:1; font-size:14px;">' + track.name + '</span>' +
|
||
'<span class="music-type">' + (track.type === 'song' ? 'Песня' : track.type === 'audiobook' ? 'Аудиокнига' : 'Мотивация') + '</span>' +
|
||
'<span class="remove" onclick="event.stopPropagation(); removeMyTrack(' + track.id + ')">×</span>' +
|
||
'</div>';
|
||
}).join('');
|
||
}
|
||
|
||
function playMyTrack(id) {
|
||
const index = myMusic.findIndex(t => t.id === id);
|
||
if (index === -1) return;
|
||
|
||
currentPlaylist = 'my';
|
||
currentTrackIndex = index;
|
||
loadTrack(index, true);
|
||
}
|
||
|
||
function removeMyTrack(id) {
|
||
myMusic = myMusic.filter(t => t.id !== id);
|
||
localStorage.setItem('myMusic', JSON.stringify(myMusic));
|
||
renderMyPlaylist();
|
||
}
|
||
|
||
function loadTrack(index, isMyMusic = false) {
|
||
let playlist;
|
||
if (isMyMusic || currentPlaylist === 'my') {
|
||
playlist = myMusic;
|
||
if (isMyMusic) currentPlaylist = 'my';
|
||
} else {
|
||
playlist = playlists[currentPlaylist];
|
||
}
|
||
|
||
if (!playlist || playlist.length === 0) return;
|
||
|
||
const track = playlist[index];
|
||
document.getElementById('now-playing').textContent = '🎵 ' + track.name;
|
||
|
||
if (player && player.loadVideoById) {
|
||
const videoId = track.videoId || track.url.split('v=')[1].split('&')[0];
|
||
player.loadVideoById(videoId);
|
||
player.setVolume(70);
|
||
}
|
||
|
||
updatePlayButton();
|
||
if (currentPlaylist === 'my') renderMyPlaylist();
|
||
}
|
||
|
||
function loadTrack(index) {
|
||
const playlist = playlists[currentPlaylist];
|
||
if (!playlist || playlist.length === 0) return;
|
||
|
||
const track = playlist[index];
|
||
document.getElementById('now-playing').textContent = '🎵 ' + track.name;
|
||
|
||
if (player && player.loadVideoById) {
|
||
const videoId = track.url.split('v=')[1].split('&')[0];
|
||
player.loadVideoById(videoId);
|
||
player.setVolume(70);
|
||
}
|
||
|
||
updatePlayButton();
|
||
}
|
||
|
||
function togglePlay() {
|
||
if (!player) {
|
||
initPlayer();
|
||
setTimeout(() => {
|
||
loadTrack(currentTrackIndex);
|
||
isPlaying = true;
|
||
updatePlayButton();
|
||
document.getElementById('equalizer').classList.remove('off');
|
||
}, 500);
|
||
return;
|
||
}
|
||
|
||
if (isPlaying) {
|
||
player.pauseVideo();
|
||
document.getElementById('equalizer').classList.add('off');
|
||
} else {
|
||
player.playVideo();
|
||
document.getElementById('equalizer').classList.remove('off');
|
||
}
|
||
isPlaying = !isPlaying;
|
||
updatePlayButton();
|
||
}
|
||
|
||
function nextTrack() {
|
||
const playlist = playlists[currentPlaylist];
|
||
currentTrackIndex = (currentTrackIndex + 1) % playlist.length;
|
||
loadTrack(currentTrackIndex);
|
||
isPlaying = true;
|
||
document.getElementById('equalizer').classList.remove('off');
|
||
}
|
||
|
||
function prevTrack() {
|
||
const playlist = playlists[currentPlaylist];
|
||
currentTrackIndex = (currentTrackIndex - 1 + playlist.length) % playlist.length;
|
||
loadTrack(currentTrackIndex);
|
||
isPlaying = true;
|
||
document.getElementById('equalizer').classList.remove('off');
|
||
}
|
||
|
||
function setVolume(value) {
|
||
if (player && player.setVolume) {
|
||
player.setVolume(value);
|
||
}
|
||
}
|
||
|
||
function updatePlayButton() {
|
||
document.getElementById('play-btn').textContent = isPlaying ? '⏸' : '▶';
|
||
}
|
||
|
||
// === ДАННЫЕ: УПРАЖНЕНИЯ С ВИДЕО ===
|
||
const exercises = [
|
||
// Осанка и спина
|
||
{ id: 1, name: "Кошка-корова", category: "posture", focus: "Гиперлордоз, гибкость спины", time: "2 мин", reps: "10-12 повторений", video: "https://www.youtube.com/embed/2qhJb8SvHjM", desc: "Медленно прогибай спину вверх, затем вниз. Дыхание ровное." },
|
||
{ id: 2, name: "Стена у стены", category: "posture", focus: "Осанка", time: "1 мин", reps: "3 подхода", video: "https://www.youtube.com/embed/k_FZCvsL53w", desc: "Встань спиной к стене, прижми затылок, лопатки, ягодицы и пятки." },
|
||
{ id: 3, name: "Лодочка", category: "posture", focus: "Спина, осанка", time: "1 мин", reps: "10 повторений", video: "https://www.youtube.com/embed/4K0e1EjwRnM", desc: "Лёжа на животе, одновременно поднимай руки и ноги." },
|
||
{ id: 4, name: "Тяга к стене", category: "posture", focus: "Осанка, плечи", time: "2 мин", reps: "15 повторений", video: "https://www.youtube.com/embed/aS5C2nQa3vM", desc: "Стоя у стены, своди лопатки и тянись руками вверх." },
|
||
{ id: 5, name: "Планка на предплечьях", category: "posture", focus: "Кор, осанка", time: "30-60 сек", reps: "3 подхода", video: "https://www.youtube.com/embed/pSHjTRCQxIw", desc: "Держи тело ровно, не прогибай поясницу." },
|
||
|
||
// Живот и бока
|
||
{ id: 6, name: "Вакуум", category: "abs", focus: "Плоский живот", time: "2 мин", reps: "5 подходов по 15 сек", video: "https://www.youtube.com/embed/8QcXlB6kXhE", desc: "Выдохни весь воздух, втяни живот под рёбра, держи." },
|
||
{ id: 7, name: "Велосипед", category: "abs", focus: "Косые мышцы, бока", time: "2 мин", reps: "20 повторений", video: "https://www.youtube.com/embed/1obhK7pOwEw", desc: "Лёжа на спине, крути педали, касайся локтем противоположного колена." },
|
||
{ id: 8, name: "Скручивания", category: "abs", focus: "Пресс", time: "2 мин", reps: "15-20 повторений", video: "https://www.youtube.com/embed/Xyd_fa5zoEU", desc: "Поднимай только лопатки, поясница прижата." },
|
||
{ id: 9, name: "Боковая планка", category: "abs", focus: "Бока, косые", time: "30 сек", reps: "3 подхода на сторону", video: "https://www.youtube.com/embed/3wVknM4sLgM", desc: "Держи тело в линию, не опускай таз." },
|
||
{ id: 10, name: "Ножницы", category: "abs", focus: "Нижний пресс", time: "1 мин", reps: "3 подхода", video: "https://www.youtube.com/embed/02eKNa3NOOo", desc: "Лёжа на спине, скрещивай ноги в воздухе." },
|
||
|
||
// Руки
|
||
{ id: 11, name: "Отжимания от стены", category: "arms", focus: "Трицепс, грудь", time: "2 мин", reps: "15 повторений", video: "https://www.youtube.com/embed/IODxDxX7oi4", desc: "Чем дальше ноги от стены, тем сложнее." },
|
||
{ id: 12, name: "Обратные отжимания", category: "arms", focus: "Трицепс", time: "2 мин", reps: "12 повторений", video: "https://www.youtube.com/embed/6pS5E1y5_7E", desc: "Сидя на полу, руки сзади на стуле, опускай таз." },
|
||
{ id: 13, name: "Круговые вращения", category: "arms", focus: "Плечи", time: "1 мин", reps: "20 вперёд, 20 назад", video: "https://www.youtube.com/embed/qX9YfKzIwHs", desc: "Руки в стороны, делай маленькие круги." },
|
||
{ id: 14, name: "Боксирование", category: "arms", focus: "Руки, кардио", time: "2 мин", reps: "50 ударов", video: "https://www.youtube.com/embed/hP2uH4XnJdM", desc: "Быстро боксируй в воздухе, держи темп." },
|
||
|
||
// Ноги и ягодицы
|
||
{ id: 15, name: "Приседания", category: "legs", focus: "Ноги, ягодицы", time: "3 мин", reps: "20 повторений", video: "https://www.youtube.com/embed/U0t2KK8vLzU", desc: "Спина ровная, колени не выходят за носки." },
|
||
{ id: 16, name: "Выпады", category: "legs", focus: "Ноги, ягодицы", time: "3 мин", reps: "12 на ногу", video: "https://www.youtube.com/embed/QOVaTkbz9fA", desc: "Шагай вперёд, опускай колено почти до пола." },
|
||
{ id: 17, name: "Ягодичный мост", category: "legs", focus: "Ягодицы", time: "2 мин", reps: "20 повторений", video: "https://www.youtube.com/embed/7iI4oVXQkXQ", desc: "Лёжа на спине, поднимай таз, сжимай ягодицы." },
|
||
{ id: 18, name: "Махи ногой", category: "legs", focus: "Ягодицы, бока", time: "2 мин", reps: "15 на ногу", video: "https://www.youtube.com/embed/4vA8R0eXzQY", desc: "Стоя на четвереньках, поднимай ногу в сторону." },
|
||
|
||
// Кардио
|
||
{ id: 19, name: "Джампинг Джек", category: "cardio", focus: "Сжигание жира", time: "2 мин", reps: "40 повторений", video: "https://www.youtube.com/embed/c4DAnljDykF", desc: "Прыжки с хлопком над головой." },
|
||
{ id: 20, name: "Бег на месте", category: "cardio", focus: "Кардио", time: "3 мин", reps: "Высоко поднимай колени", video: "https://www.youtube.com/embed/2qTF3S1Qh8M", desc: "Быстрый темп, руки работают." },
|
||
{ id: 21, name: "Бёрпи (облегчённый)", category: "cardio", focus: "Всё тело", time: "2 мин", reps: "10 повторений", video: "https://www.youtube.com/embed/auBL5Jk54gw", desc: "Присядь, шаг назад в планку, шаг вперёд, прыжок." }
|
||
];
|
||
|
||
// === ПЛАН НА 8 НЕДЕЛЬ ===
|
||
const workoutPlan = [
|
||
// Неделя 1-2: Адаптация
|
||
{ week: 1, days: [
|
||
{ type: "Осанка + Пресс", exercises: [1, 2, 5, 6, 7, 8] },
|
||
{ type: "Руки + Кардио", exercises: [11, 12, 13, 14, 19, 20] },
|
||
{ type: "Ноги + Ягодицы", exercises: [15, 16, 17, 18] },
|
||
{ type: "Осанка + Пресс", exercises: [1, 3, 4, 6, 9, 10] },
|
||
{ type: "Руки + Кардио", exercises: [11, 12, 13, 14, 19] },
|
||
{ type: "Полная тренировка", exercises: [2, 5, 7, 15, 17, 20] },
|
||
{ type: "Отдых / Растяжка", exercises: [] }
|
||
]},
|
||
// Неделя 3-4: Увеличение интенсивности
|
||
{ week: 2, days: [
|
||
{ type: "Осанка + Пресс", exercises: [1, 2, 3, 6, 7, 8, 9] },
|
||
{ type: "Руки + Кардио", exercises: [11, 12, 13, 14, 19, 20] },
|
||
{ type: "Ноги + Ягодицы", exercises: [15, 16, 17, 18] },
|
||
{ type: "Осанка + Пресс", exercises: [1, 4, 5, 6, 8, 10] },
|
||
{ type: "Руки + Кардио", exercises: [11, 12, 13, 14, 19, 20] },
|
||
{ type: "Полная тренировка", exercises: [2, 3, 7, 15, 17, 21] },
|
||
{ type: "Отдых / Растяжка", exercises: [] }
|
||
]},
|
||
// Неделя 5-6: Интенсив
|
||
{ week: 3, days: [
|
||
{ type: "Осанка + Пресс", exercises: [1, 2, 3, 4, 6, 7, 8, 9] },
|
||
{ type: "Руки + Кардио", exercises: [11, 12, 13, 14, 19, 20, 21] },
|
||
{ type: "Ноги + Ягодицы", exercises: [15, 16, 17, 18] },
|
||
{ type: "Осанка + Пресс", exercises: [1, 3, 5, 6, 8, 9, 10] },
|
||
{ type: "Руки + Кардио", exercises: [11, 12, 13, 14, 19, 20] },
|
||
{ type: "Полная тренировка", exercises: [2, 4, 7, 15, 16, 17, 21] },
|
||
{ type: "Отдых / Растяжка", exercises: [] }
|
||
]},
|
||
// Неделя 7-8: Финал
|
||
{ week: 4, days: [
|
||
{ type: "Осанка + Пресс", exercises: [1, 2, 3, 4, 5, 6, 7, 8, 9] },
|
||
{ type: "Руки + Кардио", exercises: [11, 12, 13, 14, 19, 20, 21] },
|
||
{ type: "Ноги + Ягодицы", exercises: [15, 16, 17, 18] },
|
||
{ type: "Осанка + Пресс", exercises: [1, 3, 4, 5, 6, 8, 9, 10] },
|
||
{ type: "Руки + Кардио", exercises: [11, 12, 13, 14, 19, 20, 21] },
|
||
{ type: "Полная тренировка", exercises: [2, 3, 4, 7, 15, 16, 17, 18, 21] },
|
||
{ type: "Отдых / Растяжка", exercises: [] }
|
||
]}
|
||
];
|
||
|
||
// Повторить недели 5-8 как 3-4
|
||
for (let i = 4; i < 8; i++) {
|
||
workoutPlan[i] = workoutPlan[i - 2];
|
||
}
|
||
|
||
// === СОСТОЯНИЕ ===
|
||
let currentWeek = 0;
|
||
let progressData = JSON.parse(localStorage.getItem('madinaProgress') || '{"entries":[],"completedDays":[],"water":[],"waterToday":0,"habits":{}}');
|
||
|
||
// === ПРИВЫЧКИ ===
|
||
const habitsList = [
|
||
{ id: 'water', icon: '💧', name: 'Выпить 8 стаканов воды' },
|
||
{ id: 'workout', icon: '💪', name: 'Тренировка по плану' },
|
||
{ id: 'breakfast', icon: '🍳', name: 'Здоровый завтрак' },
|
||
{ id: 'no_sugar', icon: '🚫', name: 'Без сахара и сладкого' },
|
||
{ id: 'sleep', icon: '😴', name: 'Сон 7-8 часов' },
|
||
{ id: 'no_late', icon: '🕖', name: 'Ужин до 19:00' },
|
||
{ id: 'walk', icon: '🚶', name: 'Прогулка 30 мин' },
|
||
{ id: 'stretch', icon: '🧘', name: 'Растяжка утром' }
|
||
];
|
||
|
||
// === ИНИЦИАЛИЗАЦИЯ ===
|
||
function init() {
|
||
renderTodayWorkout();
|
||
renderCatalog('all');
|
||
renderCalendar();
|
||
renderProgress();
|
||
}
|
||
|
||
// === СЕКЦИИ ===
|
||
function showSection(id) {
|
||
document.querySelectorAll('.section').forEach(s => s.classList.remove('active'));
|
||
document.querySelectorAll('.nav button').forEach(b => b.classList.remove('active'));
|
||
document.getElementById(id).classList.add('active');
|
||
event.target.classList.add('active');
|
||
}
|
||
|
||
// === СЕГОДНЯ ===
|
||
function getTodayWorkout() {
|
||
const startDate = new Date('2026-08-10');
|
||
const today = new Date();
|
||
const diffDays = Math.floor((today - startDate) / (1000 * 60 * 60 * 24));
|
||
const weekNum = Math.floor(diffDays / 7);
|
||
const dayNum = diffDays % 7;
|
||
|
||
if (weekNum >= 8) return workoutPlan[7].days[dayNum];
|
||
if (weekNum < 0) return workoutPlan[0].days[dayNum];
|
||
|
||
return workoutPlan[weekNum].days[dayNum];
|
||
}
|
||
|
||
function renderTodayWorkout() {
|
||
const today = getTodayWorkout();
|
||
const focusMap = {
|
||
'Осанка': 'Осанка и спина',
|
||
'Пресс': 'Живот и бока',
|
||
'Руки': 'Руки',
|
||
'Кардио': 'Кардио',
|
||
'Ноги': 'Ноги и ягодицы'
|
||
};
|
||
|
||
let focusText = today.type.split('+').map(s => focusMap[s.trim()] || s).join(', ');
|
||
document.getElementById('today-focus').textContent = focusText || today.type;
|
||
|
||
const container = document.getElementById('today-workout');
|
||
if (today.exercises.length === 0) {
|
||
container.innerHTML = '<div class="workout-card"><h3>🧘 Сегодня день отдыха!</h3><p>Сделай лёгкую растяжку или прогулку.</p></div>';
|
||
return;
|
||
}
|
||
|
||
container.innerHTML = '<div class="workout-card"><h3>📋 Программа на сегодня: ' + today.type + '</h3>' +
|
||
today.exercises.map(exId => {
|
||
const ex = exercises.find(e => e.id === exId);
|
||
return '<div class="exercise">' +
|
||
'<h4>' + ex.name + '</h4>' +
|
||
'<div class="video-placeholder" onclick="openVideo(' + ex.id + ')">Смотреть видео</div>' +
|
||
'<div class="exercise-meta">' +
|
||
'<span>⏱ ' + (ex.time || ex.reps) + '</span>' +
|
||
'<span>🎯 ' + ex.focus + '</span>' +
|
||
'</div>' +
|
||
'<p>' + ex.desc + '</p>' +
|
||
'</div>';
|
||
}).join('') +
|
||
'</div>';
|
||
}
|
||
|
||
function markTodayDone() {
|
||
const todayStr = new Date().toDateString();
|
||
if (!progressData.completedDays.includes(todayStr)) {
|
||
progressData.completedDays.push(todayStr);
|
||
localStorage.setItem('madinaProgress', JSON.stringify(progressData));
|
||
alert('🎉 Молодец! Тренировка отмечена!');
|
||
renderCalendar();
|
||
renderProgress();
|
||
} else {
|
||
alert('✅ Уже отмечено!');
|
||
}
|
||
}
|
||
|
||
// === КАТАЛОГ ===
|
||
function filterCatalog(category) {
|
||
document.querySelectorAll('.category-filter button').forEach(b => b.classList.remove('active'));
|
||
event.target.classList.add('active');
|
||
renderCatalog(category);
|
||
}
|
||
|
||
function renderCatalog(category) {
|
||
const filtered = category === 'all' ? exercises : exercises.filter(e => e.category === category);
|
||
document.getElementById('exercise-grid').innerHTML = filtered.map(ex =>
|
||
'<div class="exercise-card">' +
|
||
'<div class="video" onclick="openVideo(' + ex.id + ')">▶</div>' +
|
||
'<div class="info">' +
|
||
'<h4>' + ex.name + '</h4>' +
|
||
'<p>' + ex.desc + '</p>' +
|
||
'<div class="meta">' +
|
||
'<span>🎯 ' + ex.focus + '</span>' +
|
||
'<span>⏱ ' + (ex.time || ex.reps) + '</span>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'</div>'
|
||
).join('');
|
||
}
|
||
|
||
// === КАЛЕНДАРЬ ===
|
||
function changeWeek(delta) {
|
||
currentWeek = Math.max(0, Math.min(7, currentWeek + delta));
|
||
document.getElementById('week-label').textContent = 'Неделя ' + (currentWeek + 1);
|
||
renderCalendar();
|
||
}
|
||
|
||
function renderCalendar() {
|
||
const grid = document.getElementById('calendar-grid');
|
||
const plan = workoutPlan[currentWeek];
|
||
const today = new Date();
|
||
const startDate = new Date('2026-08-10');
|
||
const currentDay = Math.floor((today - startDate) / (1000 * 60 * 60 * 24));
|
||
|
||
grid.innerHTML = plan.days.map((day, i) => {
|
||
const absDay = currentWeek * 7 + i;
|
||
const isToday = absDay === currentDay && currentWeek <= 7;
|
||
const isDone = progressData.completedDays.some(d => {
|
||
const completedDate = new Date(d);
|
||
const completedDay = Math.floor((completedDate - startDate) / (1000 * 60 * 60 * 24));
|
||
return completedDay === absDay;
|
||
});
|
||
|
||
return '<div class="calendar-day' + (isToday ? ' today' : '') + (isDone ? ' done' : '') + '">' +
|
||
'<div class="day-num">' + (i + 1) + '</div>' +
|
||
'<div class="workout-type">' + day.type + '</div>' +
|
||
(isDone ? '<div style="margin-top:5px; font-size:20px;">✅</div>' : '') +
|
||
'</div>';
|
||
}).join('');
|
||
}
|
||
|
||
// === ТРЕКЕР ===
|
||
function addProgress() {
|
||
const weight = document.getElementById('weight').value;
|
||
const waist = document.getElementById('waist').value;
|
||
const hips = document.getElementById('hips').value;
|
||
const arms = document.getElementById('arms').value;
|
||
|
||
if (!weight && !waist && !hips && !arms) {
|
||
alert('Введи хотя бы одно значение');
|
||
return;
|
||
}
|
||
|
||
progressData.entries.push({
|
||
date: new Date().toISOString(),
|
||
weight, waist, hips, arms
|
||
});
|
||
localStorage.setItem('madinaProgress', JSON.stringify(progressData));
|
||
|
||
document.getElementById('weight').value = '';
|
||
document.getElementById('waist').value = '';
|
||
document.getElementById('hips').value = '';
|
||
document.getElementById('arms').value = '';
|
||
|
||
renderProgress();
|
||
alert('✅ Прогресс записан!');
|
||
}
|
||
|
||
function renderProgress() {
|
||
const entries = progressData.entries.sort((a, b) => new Date(b.date) - new Date(a.date));
|
||
const completed = progressData.completedDays.length;
|
||
|
||
const startWeight = entries[entries.length - 1]?.weight || 65;
|
||
const currentWeight = entries[0]?.weight || 65;
|
||
const lost = (startWeight - currentWeight).toFixed(1);
|
||
|
||
document.getElementById('progress-stats').innerHTML =
|
||
'<div class="stat-card"><div class="value">' + completed + '</div><div class="label">Тренировок выполнено</div></div>' +
|
||
'<div class="stat-card"><div class="value">' + startWeight + '</div><div class="label">Начальный вес</div></div>' +
|
||
'<div class="stat-card"><div class="value">' + currentWeight + '</div><div class="label">Текущий вес</div></div>' +
|
||
'<div class="stat-card"><div class="value">' + lost + '</div><div class="label">Сброшено (кг)</div></div>';
|
||
|
||
document.getElementById('progress-history').innerHTML = entries.length > 0 ?
|
||
'<h3>История замеров</h3>' + entries.map(e =>
|
||
'<div style="background:#f8f9fc; padding:15px; border-radius:10px; margin:10px 0;">' +
|
||
'<strong>' + new Date(e.date).toLocaleDateString('ru') + '</strong>: ' +
|
||
(e.weight ? e.weight + ' кг, ' : '') +
|
||
(e.waist ? 'талия ' + e.waist + ' см, ' : '') +
|
||
(e.hips ? 'бёдра ' + e.hips + ' см, ' : '') +
|
||
(e.arms ? 'руки ' + e.arms + ' см' : '') +
|
||
'</div>'
|
||
).join('') : '<p>Пока нет записей. Заполни данные выше!</p>';
|
||
|
||
renderNutrition();
|
||
renderWeightChart();
|
||
}
|
||
|
||
function renderWeightChart() {
|
||
const canvas = document.getElementById('weight-chart');
|
||
if (!canvas) return;
|
||
|
||
const ctx = canvas.getContext('2d');
|
||
const rect = canvas.getBoundingClientRect();
|
||
canvas.width = rect.width;
|
||
canvas.height = rect.height;
|
||
|
||
const entries = progressData.entries.sort((a, b) => new Date(a.date) - new Date(b.date));
|
||
const startDate = new Date('2026-08-10');
|
||
const totalWeeks = 8;
|
||
const startWeight = 65;
|
||
const targetWeight = 58;
|
||
|
||
// Данные для графика
|
||
const weights = [];
|
||
const weeks = [];
|
||
|
||
for (let w = 0; w <= totalWeeks; w++) {
|
||
weeks.push(w);
|
||
// Целевая линия: 65 - (w * 7/8)
|
||
weights.push({
|
||
week: w,
|
||
target: startWeight - (w * (startWeight - targetWeight) / totalWeeks),
|
||
actual: null
|
||
});
|
||
}
|
||
|
||
// Добавляем фактические замеры
|
||
entries.forEach(e => {
|
||
const date = new Date(e.date);
|
||
const daysFromStart = (date - startDate) / (1000 * 60 * 60 * 24);
|
||
const week = Math.min(8, Math.max(0, daysFromStart / 7));
|
||
|
||
if (e.weight) {
|
||
const weekIndex = Math.round(week);
|
||
if (weekIndex >= 0 && weekIndex <= 8) {
|
||
weights[weekIndex].actual = parseFloat(e.weight);
|
||
}
|
||
}
|
||
});
|
||
|
||
// Очистка
|
||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||
|
||
// Настройки
|
||
const padding = 40;
|
||
const chartWidth = canvas.width - padding * 2;
|
||
const chartHeight = canvas.height - padding * 2;
|
||
const weightRange = 10; // 55-75 кг
|
||
const minWeight = 55;
|
||
|
||
function x(w) { return padding + (w / totalWeeks) * chartWidth; }
|
||
function y(weight) { return padding + chartHeight - ((weight - minWeight) / weightRange) * chartHeight; }
|
||
|
||
// Сетка
|
||
ctx.strokeStyle = '#e0e0e5';
|
||
ctx.lineWidth = 1;
|
||
for (let w = 0; w <= totalWeeks; w += 2) {
|
||
ctx.beginPath();
|
||
ctx.moveTo(x(w), padding);
|
||
ctx.lineTo(x(w), canvas.height - padding);
|
||
ctx.stroke();
|
||
}
|
||
for (let wt = 56; wt <= 74; wt += 2) {
|
||
ctx.beginPath();
|
||
ctx.moveTo(padding, y(wt));
|
||
ctx.lineTo(canvas.width - padding, y(wt));
|
||
ctx.stroke();
|
||
}
|
||
|
||
// Целевая линия (красная пунктирная)
|
||
ctx.strokeStyle = '#f5576c';
|
||
ctx.lineWidth = 3;
|
||
ctx.setLineDash([10, 5]);
|
||
ctx.beginPath();
|
||
ctx.moveTo(x(0), y(startWeight));
|
||
ctx.lineTo(x(8), y(targetWeight));
|
||
ctx.stroke();
|
||
ctx.setLineDash([]);
|
||
|
||
// Фактические замеры (синяя линия)
|
||
ctx.strokeStyle = '#667eea';
|
||
ctx.lineWidth = 3;
|
||
ctx.beginPath();
|
||
let started = false;
|
||
for (let w = 0; w <= 8; w++) {
|
||
if (weights[w].actual !== null) {
|
||
if (!started) {
|
||
ctx.moveTo(x(w), y(weights[w].actual));
|
||
started = true;
|
||
} else {
|
||
ctx.lineTo(x(w), y(weights[w].actual));
|
||
}
|
||
}
|
||
}
|
||
ctx.stroke();
|
||
|
||
// Точки замеров
|
||
for (let w = 0; w <= 8; w++) {
|
||
if (weights[w].actual !== null) {
|
||
ctx.fillStyle = '#667eea';
|
||
ctx.beginPath();
|
||
ctx.arc(x(w), y(weights[w].actual), 6, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
}
|
||
}
|
||
|
||
// Подписи
|
||
ctx.fillStyle = '#667eea';
|
||
ctx.font = 'bold 14px sans-serif';
|
||
ctx.fillText('Цель: 58 кг', canvas.width - padding - 100, y(targetWeight) - 10);
|
||
|
||
ctx.fillStyle = '#667eea';
|
||
ctx.font = 'bold 14px sans-serif';
|
||
ctx.fillText('Старт: 65 кг', padding, y(startWeight) - 10);
|
||
}
|
||
|
||
// === ПИТАНИЕ ===
|
||
const productsCalories = {
|
||
'яблоко': 52, 'груша': 57, 'банан': 89, 'апельсин': 47, 'виноград': 67,
|
||
'курица': 165, 'куриная грудка': 110, 'рыба': 206, 'тунец': 132, 'лосось': 208,
|
||
'яйцо': 155, 'овсянка': 389, 'гречка': 343, 'рис': 130, 'картофель': 77,
|
||
'творог': 98, 'йогурт': 59, 'кефир': 41, 'молоко': 42, 'сыр': 402,
|
||
'хлеб': 265, 'хлебец': 310, 'орехи': 607, 'миндаль': 579, 'мёд': 304,
|
||
'помидор': 18, 'огурец': 16, 'капуста': 25, 'морковь': 41, 'брокколи': 34
|
||
};
|
||
|
||
function renderNutrition() {
|
||
// Вода
|
||
const todayStr = new Date().toDateString();
|
||
const waterToday = progressData.waterToday || 0;
|
||
const totalWater = progressData.water ? progressData.water.length : 0;
|
||
|
||
document.getElementById('water-count').textContent = waterToday;
|
||
document.getElementById('total-water').textContent = totalWater;
|
||
|
||
const glassesContainer = document.getElementById('water-glasses');
|
||
glassesContainer.innerHTML = '';
|
||
for (let i = 0; i < 8; i++) {
|
||
const glass = document.createElement('span');
|
||
glass.textContent = i < waterToday ? '💧' : '🥛';
|
||
glass.style.fontSize = '24px';
|
||
glassesContainer.appendChild(glass);
|
||
}
|
||
|
||
// Дни отслеживания
|
||
const uniqueDates = [...new Set(progressData.entries.map(e => new Date(e.date).toDateString()))];
|
||
document.getElementById('days-tracked').textContent = uniqueDates.length;
|
||
|
||
// Средний вес
|
||
if (progressData.entries.length > 0) {
|
||
const avg = progressData.entries.reduce((sum, e) => sum + (parseFloat(e.weight) || 0), 0) / progressData.entries.length;
|
||
document.getElementById('avg-weight').textContent = avg.toFixed(1);
|
||
}
|
||
|
||
renderHabits();
|
||
}
|
||
|
||
function renderHabits() {
|
||
const todayStr = new Date().toDateString();
|
||
const container = document.getElementById('habits-list');
|
||
|
||
if (!container) return;
|
||
|
||
// Инициализация сегодняшних привычек
|
||
if (!progressData.habits[todayStr]) {
|
||
progressData.habits[todayStr] = {};
|
||
}
|
||
|
||
// Чек-лист привычек
|
||
container.innerHTML = habitsList.map(h => {
|
||
const done = progressData.habits[todayStr][h.id] ? 'checked' : '';
|
||
return '<div style="background: ' + (done ? 'linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%)' : '#f8f9fc') + '; padding: 15px; border-radius: 12px; margin: 10px 0; display: flex; align-items: center; gap: 15px; cursor: pointer; transition: 0.3s;" onclick="toggleHabit(\'' + h.id + '\')">' +
|
||
'<input type="checkbox" ' + done + ' style="width: 24px; height: 24px; cursor: pointer;">' +
|
||
'<span style="font-size: 28px;">' + h.icon + '</span>' +
|
||
'<span style="font-size: 16px; flex: 1;">' + h.name + '</span>' +
|
||
(done ? '<span style="color: #28a745; font-weight: bold;">✓ Выполнено!</span>' : '') +
|
||
'</div>';
|
||
}).join('');
|
||
|
||
// Статистика
|
||
const todayHabits = progressData.habits[todayStr] || {};
|
||
const doneCount = Object.values(todayHabits).filter(v => v).length;
|
||
const percent = Math.round((doneCount / habitsList.length) * 100);
|
||
|
||
// Серия подряд
|
||
let streak = 0;
|
||
const dates = Object.keys(progressData.habits).sort((a, b) => new Date(b) - new Date(a));
|
||
for (const date of dates) {
|
||
const dayHabits = progressData.habits[date];
|
||
const allDone = habitsList.every(h => dayHabits[h.id]);
|
||
if (allDone) streak++;
|
||
else break;
|
||
}
|
||
|
||
// Всего выполнено
|
||
let total = 0;
|
||
for (const date in progressData.habits) {
|
||
total += Object.values(progressData.habits[date]).filter(v => v).length;
|
||
}
|
||
|
||
document.getElementById('habits-streak').textContent = streak;
|
||
document.getElementById('habits-total').textContent = total;
|
||
document.getElementById('habits-percent').textContent = percent + '%';
|
||
}
|
||
|
||
function toggleHabit(id) {
|
||
const todayStr = new Date().toDateString();
|
||
if (!progressData.habits[todayStr]) {
|
||
progressData.habits[todayStr] = {};
|
||
}
|
||
progressData.habits[todayStr][id] = !progressData.habits[todayStr][id];
|
||
localStorage.setItem('madinaProgress', JSON.stringify(progressData));
|
||
renderHabits();
|
||
}
|
||
|
||
function addWater() {
|
||
if (progressData.waterToday >= 8) {
|
||
alert('💧 8 стаканов уже выпито! Отличный результат!');
|
||
return;
|
||
}
|
||
progressData.waterToday++;
|
||
if (!progressData.water) progressData.water = [];
|
||
progressData.water.push(new Date().toISOString());
|
||
localStorage.setItem('madinaProgress', JSON.stringify(progressData));
|
||
renderNutrition();
|
||
}
|
||
|
||
function resetWater() {
|
||
progressData.waterToday = 0;
|
||
localStorage.setItem('madinaProgress', JSON.stringify(progressData));
|
||
renderNutrition();
|
||
}
|
||
|
||
function calculateCalories() {
|
||
const name = document.getElementById('product-name').value.toLowerCase().trim();
|
||
const grams = parseInt(document.getElementById('product-grams').value);
|
||
|
||
if (!name || !grams) {
|
||
document.getElementById('calories-result').textContent = '⚠️ Введи продукт и вес';
|
||
return;
|
||
}
|
||
|
||
// Поиск продукта в базе
|
||
let caloriesPer100 = 0;
|
||
let found = false;
|
||
|
||
for (const key in productsCalories) {
|
||
if (name.includes(key)) {
|
||
caloriesPer100 = productsCalories[key];
|
||
found = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!found) {
|
||
document.getElementById('calories-result').textContent = '❓ Продукт не найден в базе. Пример: яблоко 100г = ~52 ккал';
|
||
return;
|
||
}
|
||
|
||
const result = Math.round((caloriesPer100 * grams) / 100);
|
||
document.getElementById('calories-result').textContent =
|
||
'🍎 ' + name + ' (' + grams + 'г) = ' + result + ' ккал';
|
||
}
|
||
|
||
// === МОДАЛЬНОЕ ОКНО ===
|
||
function openVideo(id) {
|
||
const ex = exercises.find(e => e.id === id);
|
||
document.getElementById('modal-title').textContent = ex.name;
|
||
document.getElementById('modal-video').innerHTML =
|
||
'<iframe width="100%" height="400" src="' + ex.video + '" frameborder="0" allowfullscreen style="border-radius:12px;"></iframe>';
|
||
document.getElementById('modal-desc').textContent = ex.desc + ' (' + (ex.time || ex.reps) + ')';
|
||
document.getElementById('video-modal').classList.add('active');
|
||
}
|
||
|
||
function closeModal() {
|
||
document.getElementById('video-modal').classList.remove('active');
|
||
document.getElementById('modal-video').innerHTML = '';
|
||
}
|
||
|
||
// Закрытие по клику вне
|
||
document.getElementById('video-modal').addEventListener('click', function(e) {
|
||
if (e.target === this) closeModal();
|
||
});
|
||
|
||
// Инициализация плеера при загрузке
|
||
setTimeout(() => initPlayer(), 1000);
|
||
|
||
// Загрузка моей музыки
|
||
renderMyPlaylist();
|
||
|
||
init();
|
||
</script>
|
||
|
||
<!-- Скрытый iframe для музыкального плеера -->
|
||
<div id="music-player-frame" style="display:none;"></div>
|
||
</body>
|
||
</html>
|
||
</body>
|
||
</html>
|