diff --git a/frontend/css/styles.css b/frontend/css/styles.css index af0ad1a..cfe0fd7 100644 --- a/frontend/css/styles.css +++ b/frontend/css/styles.css @@ -1062,6 +1062,15 @@ select { .rec-panel { flex-shrink: 0; } +.draw-screen { + display: flex; + flex-direction: column; + height: 100%; +} +.draw-map { + flex: 1; + min-height: 200px; +} .rec-map-wrap { flex: 1; diff --git a/frontend/js/db.js b/frontend/js/db.js index f95ecdc..e30e488 100644 --- a/frontend/js/db.js +++ b/frontend/js/db.js @@ -476,11 +476,19 @@ async function getActivitiesForDate(date) { return select("SELECT * FROM activity_log WHERE date = ?1 ORDER BY time ASC", [date]); } -async function addActivity(date, time, type, desc, minutes, kcal) { - await execute( - "INSERT INTO activity_log (date, time, type, desc, minutes, kcal) VALUES (?1,?2,?3,?4,?5,?6)", - [date, time, type ?? "manual", desc, minutes ?? null, kcal ?? null] - ); +async function addActivity(date, time, type, desc, minutes, kcal, opts) { + // Build column list dynamically — new columns may not exist yet on first run + const cols = ["date", "time", "type", "desc", "minutes", "kcal"]; + const vals = [date, time, type ?? "manual", desc, minutes ?? null, kcal ?? null]; + if (opts) { + const actCols = (await select("PRAGMA table_info(activity_log)")).map(c => c.name); + if (actCols.includes("activity_type")) { cols.push("activity_type"); vals.push(opts.activity_type ?? "manual"); } + if (actCols.includes("sets") && opts.sets) { cols.push("sets"); vals.push(opts.sets); } + if (actCols.includes("reps") && opts.reps) { cols.push("reps"); vals.push(opts.reps); } + if (actCols.includes("distance_m") && opts.distance_m) { cols.push("distance_m"); vals.push(opts.distance_m); } + } + const placeholders = cols.map((_, i) => `?${i + 1}`).join(","); + await execute(`INSERT INTO activity_log (${cols.join(",")}) VALUES (${placeholders})`, vals); } async function deleteActivity(id) { @@ -1544,6 +1552,16 @@ async function runMigrations() { // Spatial index for fast 2m proximity checks await execute(`CREATE INDEX IF NOT EXISTS idx_road_lat_lon ON road_points(lat, lon)`); + // Activity types: extend activity_log with structured fields + const actCols = (await select("PRAGMA table_info(activity_log)")).map(c => c.name); + if (!actCols.includes("activity_type")) { + await execute("ALTER TABLE activity_log ADD COLUMN activity_type TEXT"); + await execute("UPDATE activity_log SET activity_type = 'manual' WHERE activity_type IS NULL"); + } + if (!actCols.includes("sets")) await execute("ALTER TABLE activity_log ADD COLUMN sets INTEGER"); + if (!actCols.includes("reps")) await execute("ALTER TABLE activity_log ADD COLUMN reps INTEGER"); + if (!actCols.includes("distance_m")) await execute("ALTER TABLE activity_log ADD COLUMN distance_m REAL"); + // Water content column for hydration tracking if (!productCols.includes("water_pct")) { await execute("ALTER TABLE products ADD COLUMN water_pct REAL"); diff --git a/frontend/js/main.js b/frontend/js/main.js index 8757f4e..9b634cb 100644 --- a/frontend/js/main.js +++ b/frontend/js/main.js @@ -9,6 +9,13 @@ const app = document.getElementById("app"); const UPDATE_BASE_URL = "https://4aiman.top/baldav"; +const ACTIVITY_MET = { squats: 6.0, jumprope: 12.3, stretch: 2.3, swim: 8.0, manual: 3.0 }; +const ACTIVITY_NAMES = { squats: "Приседания", jumprope: "Скакалка", stretch: "Растяжки", swim: "Бассейн", manual: "Другое" }; +function activityKcal(type, minutes, weightKg) { + const met = ACTIVITY_MET[type] || 3.0; + return Math.round(met * 3.5 * weightKg * minutes / 200); +} + let state = { screen: "today", date: todayIso(), @@ -393,15 +400,21 @@ async function renderToday(container) { ${s.avg_speed_kmh ? s.avg_speed_kmh.toFixed(1) + " км/ч" : ""} `; }).join("")} - ${activities.map(a => - `