trainflow / index.html
Prochu's picture
Zbyduj stronę w typescript i react, dodaj backend - Initial Deployment
ad48355 verified
// src/types/index.ts
export interface Exercise {
name: string;
sets: number;
reps: string;
type: string;
}
export interface WorkoutPlan {
duration: string;
daysPerWeek: number;
goal: string;
exercises: Exercise[];
}
export interface Question {
id: string;
question: string;
options: {
text: string;
value: string;
icon: string;
}[];
}
// src/services/workoutService.ts
import { WorkoutPlan } from '../types';
export const generateWorkoutPlan = async (answers: any): Promise<WorkoutPlan> => {
const response = await fetch('/api/workout-plan', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ answers }),
});
if (!response.ok) {
throw new Error('Failed to generate workout plan');
}
return response.json();
};
// server/index.ts
import express from 'express';
import cors from 'cors';
import { ClerkExpressRequireAuth } from '@clerk/clerk-sdk-node';
const app = express();
app.use(cors());
app.use(express.json());
// API routes
app.get('/api/workout-plan', ClerkExpressRequireAuth(), async (req, res) => {
// Generate workout plan logic here
res.json({
plan: {
duration: '4 weeks',
daysPerWeek: 4,
goal: 'Muscle Building',
exercises: [
// Exercise data
]
}
});
});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
// src/pages/MainApp.tsx
import React from 'react';
import { Outlet } from 'react-router-dom';
import BottomNav from '../components/BottomNav';
const MainApp = () => {
return (
<div className="min-h-screen bg-gradient-to-br from-gray-900 to-gray-800 text-white">
<div className="pb-20">
<Outlet />
</div>
<BottomNav />
</div>
);
};
export default MainApp;
// src/pages/LandingPage.tsx
import React from 'react';
import { useClerk } from '@clerk/clerk-react';
import { Button } from '../components/ui/button';
const LandingPage = () => {
const { openSignIn } = useClerk();
return (
<div className="min-h-screen px-4 py-8 pb-24 bg-gradient-to-br from-gray-900 to-gray-800 text-white">
<div className="max-w-6xl mx-auto">
<nav className="flex justify-between items-center py-6">
<div>
<h1 className="text-2xl font-bold">Fit<span className="text-indigo-500">AI</span></h1>
</div>
<UserButton />
</nav>
<div className="flex flex-col md:flex-row items-center justify-between mt-16">
{/* Rest of landing page content */}
<Button onClick={() => openSignIn()}>
Rozpocznij teraz
</Button>
</div>
</div>
</div>
);
};
export default LandingPage;
// src/App.tsx
import React, { useState } from 'react';
import { ClerkProvider, SignedIn, SignedOut, UserButton } from '@clerk/clerk-react';
import LandingPage from './pages/LandingPage';
import MainApp from './pages/MainApp';
import './App.css';
const clerkPubKey = process.env.REACT_APP_CLERK_PUBLISHABLE_KEY || '';
function App() {
return (
<ClerkProvider publishableKey={clerkPubKey}>
<SignedIn>
<MainApp />
</SignedIn>
<SignedOut>
<LandingPage />
</SignedOut>
</ClerkProvider>
);
}
export default App;
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FitAI - Twój inteligentny plan treningowy</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdn.jsdelivr.net/npm/@clerk/clerk-js@latest/dist/clerk.browser.js"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#6366f1',
secondary: '#8b5cf6',
dark: '#1e293b',
light: '#f8fafc'
}
}
}
}
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
body {
font-family: 'Poppins', sans-serif;
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
}
.card {
backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.08);
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}
.exercise-card {
transition: all 0.3s ease;
}
.exercise-card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 20px rgba(0, 0, 0, 0.2);
}
.progress-bar {
height: 8px;
border-radius: 4px;
overflow: hidden;
}
.progress-fill {
height: 100%;
border-radius: 4px;
transition: width 0.5s ease-in-out;
}
.floating-btn {
box-shadow: 0 6px 20px rgba(99, 102, 241, 0.4);
transition: all 0.3s ease;
}
.floating-btn:hover {
transform: scale(1.05);
box-shadow: 0 8px 25px rgba(99, 102, 241, 0.6);
}
.animate-pulse-slow {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.slide-in {
animation: slideIn 0.5s ease-out forwards;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.sticky-nav {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
padding: 12px 0;
z-index: 100;
display: flex;
justify-content: center;
height: 60px; /* Stała wysokość nawigacji */
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.3); /* Delikatny cień dla lepszego oddzielenia */
}
.clerk-user-button {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.clerk-user-button-trigger {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
.nav-content {
width: 100%;
max-width: 1024px;
display: flex;
justify-content: space-around;
}
.main-container {
padding-bottom: 120px; /* Zwiększamy padding aby uwzględnić nawigację */
width: 100%;
max-width: 1024px;
margin-bottom: 60px; /* Dodajemy margines na dole */
}
@media (min-width: 768px) {
.main-container {
padding: 2rem;
margin-top: 2rem;
border-radius: 20px;
background: rgba(30, 41, 59, 0.7);
backdrop-filter: blur(10px);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.exercise-card {
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.card {
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
}
</style>
</head>
<body class="text-light">
<!-- Landing Page -->
<section id="landing" class="min-h-screen px-4 py-8 pb-24"> <!-- Dodajemy pb-24 dla paddingu na dole -->
<div class="max-w-6xl mx-auto">
<nav class="flex justify-between items-center py-6">
<div>
<h1 class="text-2xl font-bold">Fit<span class="text-primary">AI</span></h1>
</div>
<div id="user-button"></div>
</nav>
<div class="flex flex-col md:flex-row items-center justify-between mt-16">
<div class="md:w-1/2 mb-12 md:mb-0">
<h2 class="text-4xl md:text-5xl font-bold mb-6">Twój inteligentny <span class="text-primary">plan treningowy</span></h2>
<p class="text-lg opacity-80 mb-8">Odpowiedz na kilka pytań, a nasze AI stworzy dla Ciebie spersonalizowany plan treningowy dostosowany do Twoich celów i możliwości.</p>
<button id="getStartedBtn" class="px-8 py-3 bg-primary rounded-xl font-medium flex items-center space-x-2 floating-btn">
<span>Rozpocznij teraz</span>
<i class="fas fa-arrow-right"></i>
</button>
</div>
<div class="md:w-1/2">
<div class="card p-8 relative overflow-hidden">
<div class="absolute -top-10 -right-10 w-32 h-32 rounded-full bg-primary/20"></div>
<div class="absolute -bottom-8 -left-8 w-24 h-24 rounded-full bg-secondary/20"></div>
<img src="https://images.unsplash.com/photo-1571019613454-1cb2f99b2d8b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80"
alt="Fitness" class="w-full h-auto rounded-lg">
</div>
</div>
</div>
<div class="mt-24">
<h3 class="text-2xl font-bold mb-8 text-center">Dlaczego FitAI?</h3>
<div class="grid md:grid-cols-3 gap-8">
<div class="card p-6">
<div class="w-12 h-12 rounded-full bg-primary/20 flex items-center justify-center mb-4">
<i class="fas fa-brain text-primary"></i>
</div>
<h4 class="font-bold mb-2">AI-Powered</h4>
<p class="opacity-80">Nasze algorytmy AI tworzą idealny plan treningowy dostosowany do Ciebie.</p>
</div>
<div class="card p-6">
<div class="w-12 h-12 rounded-full bg-secondary/20 flex items-center justify-center mb-4">
<i class="fas fa-bolt text-secondary"></i>
</div>
<h4 class="font-bold mb-2">Szybkie efekty</h4>
<p class="opacity-80">Optymalizowane plany treningowe dla maksymalnych rezultatów.</p>
</div>
<div class="card p-6">
<div class="w-12 h-12 rounded-full bg-primary/20 flex items-center justify-center mb-4">
<i class="fas fa-chart-line text-primary"></i>
</div>
<h4 class="font-bold mb-2">Śledź postępy</h4>
<p class="opacity-80">Monitoruj swoje osiągnięcia i dostosowuj plan do swoich potrzeb.</p>
</div>
</div>
</div>
</div>
</section>
<!-- Main Container -->
<div id="app" class="min-h-screen px-4 py-8 main-container hidden">
<!-- Header -->
<header class="flex justify-between items-center mb-8">
<div>
<h1 class="text-2xl font-bold">Fit<span class="text-primary">AI</span></h1>
<p class="text-sm opacity-75">Inteligentny plan treningowy</p>
</div>
<div class="flex space-x-3">
<button class="w-10 h-10 rounded-full bg-primary/20 flex items-center justify-center">
<i class="fas fa-user text-primary"></i>
</button>
<button class="w-10 h-10 rounded-full bg-primary/20 flex items-center justify-center">
<i class="fas fa-cog text-primary"></i>
</button>
</div>
</header>
<!-- Main Content -->
<main>
<!-- Hero Section -->
<section class="card p-6 mb-8 relative overflow-hidden">
<div class="absolute -top-10 -right-10 w-32 h-32 rounded-full bg-primary/20"></div>
<div class="absolute -bottom-8 -left-8 w-24 h-24 rounded-full bg-secondary/20"></div>
<div class="relative z-10">
<h2 class="text-xl font-bold mb-2">Stwórz swój idealny plan treningowy</h2>
<p class="text-sm opacity-80 mb-4">Odpowiedz na kilka pytań, a nasze AI stworzy dla Ciebie spersonalizowany plan treningowy</p>
<button id="startBtn" class="w-full py-3 bg-primary rounded-xl font-medium flex items-center justify-center space-x-2 floating-btn">
<span>Rozpocznij teraz</span>
<i class="fas fa-arrow-right"></i>
</button>
</div>
</section>
<!-- Questionnaire Section -->
<section id="questionnaire" class="hidden">
<div class="card p-6 mb-6">
<div class="flex justify-between items-center mb-4">
<h3 class="font-medium">Twój plan treningowy</h3>
<span class="text-sm bg-primary/20 px-2 py-1 rounded">Krok <span id="currentStep">1</span>/5</span>
</div>
<div class="progress-bar bg-gray-700 mb-6">
<div id="progressFill" class="progress-fill bg-primary w-1/5"></div>
</div>
<div id="questionContainer">
<!-- Questions will be injected here -->
</div>
<div class="flex justify-between mt-6">
<button id="prevBtn" class="py-2 px-4 rounded-lg bg-gray-700 opacity-0 invisible">
<i class="fas fa-arrow-left mr-2"></i>Wstecz
</button>
<button id="nextBtn" class="py-2 px-4 bg-primary rounded-lg flex items-center">
<span>Dalej</span>
<i class="fas fa-arrow-right ml-2"></i>
</button>
</div>
</div>
</section>
<!-- Generating Section -->
<section id="generating" class="hidden">
<div class="card p-8 text-center">
<div class="flex justify-center mb-6">
<div class="w-16 h-16 rounded-full bg-primary/20 flex items-center justify-center animate-pulse-slow">
<i class="fas fa-brain text-2xl text-primary"></i>
</div>
</div>
<h3 class="text-xl font-bold mb-2">Tworzę Twój plan...</h3>
<p class="opacity-80 mb-6">Nasze AI analizuje Twoje odpowiedzi i tworzy idealny plan treningowy</p>
<div class="flex space-x-2 justify-center">
<div class="w-2 h-2 bg-primary rounded-full animate-pulse-slow"></div>
<div class="w-2 h-2 bg-primary rounded-full animate-pulse-slow delay-150"></div>
<div class="w-2 h-2 bg-primary rounded-full animate-pulse-slow delay-300"></div>
</div>
</div>
</section>
<!-- Results Section -->
<section id="results" class="hidden">
<div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-bold">Twój plan treningowy</h2>
<button class="w-10 h-10 rounded-full bg-primary/20 flex items-center justify-center">
<i class="fas fa-download text-primary"></i>
</button>
</div>
<div class="card p-5 mb-6">
<div class="flex justify-between mb-4">
<div>
<h3 class="font-bold">Plan na 4 tygodnie</h3>
<p class="text-sm opacity-80">Dla średniozaawansowanych</p>
</div>
<div class="bg-secondary/20 text-secondary px-3 py-1 rounded-lg text-sm font-medium">
4 dni/tydzień
</div>
</div>
<div class="grid grid-cols-2 gap-2 mb-4">
<div class="bg-gray-800/50 rounded-lg p-3 text-center">
<p class="text-sm opacity-80">Cel</p>
<p class="font-medium">Budowa mięśni</p>
</div>
<div class="bg-gray-800/50 rounded-lg p-3 text-center">
<p class="text-sm opacity-80">Czas</p>
<p class="font-medium">45-60 min</p>
</div>
</div>
<button class="w-full py-2 bg-primary/20 text-primary rounded-lg font-medium">
<i class="fas fa-sync-alt mr-2"></i>Wygeneruj ponownie
</button>
</div>
<h3 class="font-bold mb-4">Dzisiejszy trening: Górna część ciała</h3>
<div class="space-y-4">
<!-- Exercise Cards -->
<div class="exercise-card card p-4 slide-in">
<div class="flex items-start">
<div class="bg-primary/20 w-12 h-12 rounded-lg flex items-center justify-center mr-3">
<i class="fas fa-dumbbell text-primary"></i>
</div>
<div class="flex-1">
<h4 class="font-bold">Wyciskanie sztangi leżąc</h4>
<div class="flex text-sm mt-1">
<span class="bg-gray-700 px-2 py-1 rounded mr-2">4 serie</span>
<span class="bg-gray-700 px-2 py-1 rounded">8-12 powtórzeń</span>
</div>
</div>
</div>
</div>
<div class="exercise-card card p-4 slide-in">
<div class="flex items-start">
<div class="bg-secondary/20 w-12 h-12 rounded-lg flex items-center justify-center mr-3">
<i class="fas fa-dumbbell text-secondary"></i>
</div>
<div class="flex-1">
<h4 class="font-bold">Wyciskanie hantli na skosie</h4>
<div class="flex text-sm mt-1">
<span class="bg-gray-700 px-2 py-1 rounded mr-2">3 serie</span>
<span class="bg-gray-700 px-2 py-1 rounded">10-15 powtórzeń</span>
</div>
</div>
</div>
</div>
<div class="exercise-card card p-4 slide-in">
<div class="flex items-start">
<div class="bg-primary/20 w-12 h-12 rounded-lg flex items-center justify-center mr-3">
<i class="fas fa-dumbbell text-primary"></i>
</div>
<div class="flex-1">
<h4 class="font-bold">Podciąganie na drążku</h4>
<div class="flex text-sm mt-1">
<span class="bg-gray-700 px-2 py-1 rounded mr-2">4 serie</span>
<span class="bg-gray-700 px-2 py-1 rounded">6-10 powtórzeń</span>
</div>
</div>
</div>
</div>
<div class="exercise-card card p-4 slide-in">
<div class="flex items-start">
<div class="bg-secondary/20 w-12 h-12 rounded-lg flex items-center justify-center mr-3">
<i class="fas fa-dumbbell text-secondary"></i>
</div>
<div class="flex-1">
<h4 class="font-bold">Uginanie ramion ze sztangą</h4>
<div class="flex text-sm mt-1">
<span class="bg-gray-700 px-2 py-1 rounded mr-2">3 serie</span>
<span class="bg-gray-700 px-2 py-1 rounded">10-12 powtórzeń</span>
</div>
</div>
</div>
</div>
<div class="exercise-card card p-4 slide-in">
<div class="flex items-start">
<div class="bg-primary/20 w-12 h-12 rounded-lg flex items-center justify-center mr-3">
<i class="fas fa-dumbbell text-primary"></i>
</div>
<div class="flex-1">
<h4 class="font-bold">Wyciskanie francuskie</h4>
<div class="flex text-sm mt-1">
<span class="bg-gray-700 px-2 py-1 rounded mr-2">3 serie</span>
<span class="bg-gray-700 px-2 py-1 rounded">12-15 powtórzeń</span>
</div>
</div>
</div>
</div>
</div>
<div class="mt-8 flex space-x-3">
<button class="flex-1 py-3 bg-primary rounded-xl font-medium">
<i class="fas fa-play-circle mr-2"></i>Rozpocznij trening
</button>
<button class="w-12 h-12 rounded-xl bg-gray-700 flex items-center justify-center">
<i class="fas fa-calendar"></i>
</button>
</div>
</section>
</main>
</div>
<!-- Navigation -->
<nav class="sticky-nav border-t border-gray-700" id="app-nav">
<div class="nav-content px-4">
<button class="flex flex-col items-center text-primary">
<i class="fas fa-home text-lg"></i>
<span class="text-xs mt-1">Strona główna</span>
</button>
<button class="flex flex-col items-center opacity-60">
<i class="fas fa-calendar text-lg"></i>
<span class="text-xs mt-1">Kalendarz</span>
</button>
<button class="flex flex-col items-center opacity-60">
<i class="fas fa-chart-line text-lg"></i>
<span class="text-xs mt-1">Statystyki</span>
</button>
<div id="nav-user-button" class="flex flex-col items-center">
<div class="w-6 h-6 flex items-center justify-center">
<i class="fas fa-user text-lg"></i>
</div>
<span class="text-xs mt-1">Profil</span>
</div>
</nav>
<script>
// App state
const state = {
currentStep: 0,
answers: {},
questions: [
{
question: "Jaki jest Twój główny cel treningowy?",
options: [
{text: "Budowa mięśni", icon: "fas fa-dumbbell"},
{text: "Redukcja tkanki tłuszczowej", icon: "fas fa-weight-scale"},
{text: "Poprawa wytrzymałości", icon: "fas fa-heart-pulse"},
{text: "Ogólna sprawność", icon: "fas fa-person-running"}
]
},
{
question: "Jaki jest Twój poziom zaawansowania?",
options: [
{text: "Początkujący", icon: "fas fa-seedling"},
{text: "Średniozaawansowany", icon: "fas fa-chart-line"},
{text: "Zaawansowany", icon: "fas fa-fire"}
]
},
{
question: "Ile dni w tygodniu chcesz trenować?",
options: [
{text: "2 dni", icon: "fas fa-calendar"},
{text: "3 dni", icon: "fas fa-calendar"},
{text: "4 dni", icon: "fas fa-calendar"},
{text: "5+ dni", icon: "fas fa-calendar"}
]
},
{
question: "Jakie masz dostępne wyposażenie?",
options: [
{text: "Brak sprzętu", icon: "fas fa-person"},
{text: "Hantle", icon: "fas fa-dumbbell"},
{text: "Sztanga", icon: "fas fa-weight-hanging"},
{text: "Pełny zestaw siłowni", icon: "fas fa-building"}
]
},
{
question: "Ile czasu możesz poświęcić na trening?",
options: [
{text: "30 minut", icon: "fas fa-clock"},
{text: "45 minut", icon: "fas fa-clock"},
{text: "60 minut", icon: "fas fa-clock"},
{text: "90+ minut", icon: "fas fa-clock"}
]
}
]
};
// DOM Elements
const startBtn = document.getElementById('startBtn');
const questionnaire = document.getElementById('questionnaire');
const generating = document.getElementById('generating');
const results = document.getElementById('results');
const questionContainer = document.getElementById('questionContainer');
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
const currentStepEl = document.getElementById('currentStep');
const progressFill = document.getElementById('progressFill');
// Clerk Initialization
const frontendApi = 'YOUR_CLERK_FRONTEND_API_KEY'; // Replace with your Clerk Frontend API
const clerkPubKey = 'YOUR_CLERK_PUBLISHABLE_KEY'; // Replace with your Clerk Publishable Key
const clerk = new Clerk(frontendApi);
// Initialize Clerk
clerk.load({
publishableKey: clerkPubKey
}).then(() => {
// Mount user buttons
clerk.mountUserButton('#user-button');
clerk.mountUserButton('#nav-user-button');
// Check auth state
clerk.addListener(({ user }) => {
if (user) {
document.getElementById('landing').classList.add('hidden');
document.getElementById('app').classList.remove('hidden');
document.getElementById('app-nav').classList.remove('hidden');
} else {
document.getElementById('landing').classList.remove('hidden');
document.getElementById('app').classList.add('hidden');
document.getElementById('app-nav').classList.add('hidden');
}
});
});
// Initialize the app
function initApp() {
startBtn.addEventListener('click', startQuestionnaire);
nextBtn.addEventListener('click', goToNextStep);
prevBtn.addEventListener('click', goToPrevStep);
// Landing page button
document.getElementById('getStartedBtn').addEventListener('click', () => {
clerk.openSignIn();
});
}
// Start questionnaire
function startQuestionnaire() {
document.querySelector('section:first-child').classList.add('hidden');
questionnaire.classList.remove('hidden');
renderQuestion();
}
// Render current question
function renderQuestion() {
const question = state.questions[state.currentStep];
let html = `
<h4 class="font-bold mb-4">${question.question}</h4>
<div class="space-y-3">
`;
question.options.forEach((option, index) => {
html += `
<div class="flex items-center p-3 bg-gray-800/50 rounded-lg cursor-pointer option" data-index="${index}">
<div class="w-8 h-8 rounded-full bg-primary/20 flex items-center justify-center mr-3">
<i class="${option.icon} text-primary"></i>
</div>
<span>${option.text}</span>
</div>
`;
});
html += `</div>`;
questionContainer.innerHTML = html;
// Update step indicator
currentStepEl.textContent = state.currentStep + 1;
progressFill.style.width = `${((state.currentStep + 1) / state.questions.length) * 100}%`;
// Update navigation buttons
prevBtn.classList.toggle('invisible', state.currentStep === 0);
prevBtn.classList.toggle('opacity-0', state.currentStep === 0);
if (state.currentStep === state.questions.length - 1) {
nextBtn.innerHTML = '<i class="fas fa-check mr-2"></i> Wygeneruj plan';
} else {
nextBtn.innerHTML = '<span>Dalej</span> <i class="fas fa-arrow-right ml-2"></i>';
}
// Add event listeners to options
document.querySelectorAll('.option').forEach(option => {
option.addEventListener('click', function() {
// Remove selected class from all options
document.querySelectorAll('.option').forEach(opt => {
opt.classList.remove('bg-primary/20', 'border-primary');
});
// Add selected class to clicked option
this.classList.add('bg-primary/20', 'border-primary');
// Store answer
state.answers[state.currentStep] = parseInt(this.dataset.index);
});
});
}
// Go to next step
function goToNextStep() {
if (state.answers[state.currentStep] === undefined) {
alert('Proszę wybrać odpowiedź przed przejściem dalej');
return;
}
if (state.currentStep < state.questions.length - 1) {
state.currentStep++;
renderQuestion();
} else {
// Last step - generate plan
questionnaire.classList.add('hidden');
generating.classList.remove('hidden');
// Simulate AI processing
setTimeout(() => {
generating.classList.add('hidden');
results.classList.remove('hidden');
// Animate exercise cards
const cards = document.querySelectorAll('.exercise-card');
cards.forEach((card, index) => {
card.style.animationDelay = `${index * 0.1}s`;
});
}, 3000);
}
}
// Go to previous step
function goToPrevStep() {
if (state.currentStep > 0) {
state.currentStep--;
renderQuestion();
}
}
// Initialize the app when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
initApp();
// Hide app navigation on landing page
clerk.addListener(({ user }) => {
if (user) {
document.getElementById('app-nav').classList.remove('hidden');
} else {
document.getElementById('app-nav').classList.add('hidden');
}
});
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Prochu/trainflow" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>