Raí Santos
commited on
Commit
·
87bbdf3
1
Parent(s):
65f788b
Optimized for Hugging Face Spaces
Browse files- Dockerfile +30 -50
- README.md +13 -43
- dist/app.min.js +0 -0
- dist/app.min.js.gz +2 -2
- dist/build-report.json +13 -13
- dist/index.html +1 -1
- dist/index.html.gz +2 -2
- docker-entrypoint.sh +1 -35
- package.json +1 -7
- public/app.js +6 -0
- public/index.html +1 -18
Dockerfile
CHANGED
|
@@ -1,68 +1,48 @@
|
|
| 1 |
-
#
|
| 2 |
-
|
| 3 |
-
FROM node:18-alpine AS builder
|
| 4 |
-
|
| 5 |
-
# Install curl for downloading (if needed)
|
| 6 |
-
RUN apk add --no-cache curl
|
| 7 |
|
|
|
|
| 8 |
WORKDIR /app
|
| 9 |
|
| 10 |
-
#
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
# Install ALL dependencies (including devDependencies for scripts)
|
| 14 |
-
RUN npm ci && npm cache clean --force
|
| 15 |
-
|
| 16 |
-
# Copy application files and scripts
|
| 17 |
-
COPY . .
|
| 18 |
-
|
| 19 |
-
# Download videos and audio files (with error handling)
|
| 20 |
-
RUN npm run download || echo "Warning: Video download failed, will use CDN fallback"
|
| 21 |
-
|
| 22 |
-
# Build production assets
|
| 23 |
-
RUN npm run build || echo "Build step skipped"
|
| 24 |
-
|
| 25 |
-
# Stage 2: Production image
|
| 26 |
-
FROM node:18-alpine AS production
|
| 27 |
-
|
| 28 |
-
WORKDIR /app
|
| 29 |
|
| 30 |
# Copy package files
|
| 31 |
COPY package*.json ./
|
| 32 |
|
| 33 |
-
# Install
|
| 34 |
-
RUN npm ci --only=production &&
|
| 35 |
-
|
| 36 |
-
# Create non-root user for security FIRST
|
| 37 |
-
RUN addgroup -g 1001 -S nodejs && \
|
| 38 |
-
adduser -S nodejs -u 1001 -G nodejs
|
| 39 |
|
| 40 |
-
# Copy
|
| 41 |
-
COPY
|
| 42 |
-
|
|
|
|
| 43 |
|
| 44 |
-
#
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
COPY --from=builder /app/server.js ./server.js
|
| 48 |
-
COPY --from=builder /app/scripts ./scripts
|
| 49 |
|
| 50 |
-
#
|
| 51 |
-
RUN
|
|
|
|
|
|
|
| 52 |
|
| 53 |
-
# Switch to non-root user
|
| 54 |
USER nodejs
|
| 55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
# Expose port
|
| 57 |
EXPOSE 7860
|
| 58 |
|
| 59 |
-
# Set environment variables
|
| 60 |
-
ENV NODE_ENV=production
|
| 61 |
-
ENV PORT=7860
|
| 62 |
-
|
| 63 |
# Health check
|
| 64 |
-
HEALTHCHECK --interval=30s --timeout=3s --start-period=
|
| 65 |
-
CMD node -e "require('http').get('http://localhost:7860/', (
|
|
|
|
|
|
|
|
|
|
| 66 |
|
| 67 |
-
# Start
|
| 68 |
-
|
|
|
|
| 1 |
+
# Optimized Dockerfile for Hugging Face Spaces
|
| 2 |
+
FROM node:18-alpine
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
+
# Set working directory
|
| 5 |
WORKDIR /app
|
| 6 |
|
| 7 |
+
# Install only what's needed
|
| 8 |
+
RUN apk add --no-cache curl tini
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
# Copy package files
|
| 11 |
COPY package*.json ./
|
| 12 |
|
| 13 |
+
# Install dependencies (production only for smaller image)
|
| 14 |
+
RUN npm ci --only=production --quiet && \
|
| 15 |
+
npm cache clean --force
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
+
# Copy application code
|
| 18 |
+
COPY public ./public
|
| 19 |
+
COPY server.js ./
|
| 20 |
+
COPY scripts ./scripts
|
| 21 |
|
| 22 |
+
# Create directories for media (will be populated at runtime if needed)
|
| 23 |
+
RUN mkdir -p public/videos public/songs && \
|
| 24 |
+
chmod -R 755 public
|
|
|
|
|
|
|
| 25 |
|
| 26 |
+
# Non-root user for security
|
| 27 |
+
RUN addgroup -g 1001 -S nodejs && \
|
| 28 |
+
adduser -S nodejs -u 1001 -G nodejs && \
|
| 29 |
+
chown -R nodejs:nodejs /app
|
| 30 |
|
|
|
|
| 31 |
USER nodejs
|
| 32 |
|
| 33 |
+
# Environment variables
|
| 34 |
+
ENV NODE_ENV=production \
|
| 35 |
+
PORT=7860
|
| 36 |
+
|
| 37 |
# Expose port
|
| 38 |
EXPOSE 7860
|
| 39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
# Health check
|
| 41 |
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
| 42 |
+
CMD node -e "require('http').get('http://localhost:7860/', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"
|
| 43 |
+
|
| 44 |
+
# Use tini to properly handle signals
|
| 45 |
+
ENTRYPOINT ["/sbin/tini", "--"]
|
| 46 |
|
| 47 |
+
# Start server
|
| 48 |
+
CMD ["node", "server.js"]
|
README.md
CHANGED
|
@@ -89,60 +89,31 @@ Seguindo o plano à risca, você pode esperar:
|
|
| 89 |
|
| 90 |
Lembre-se: você é mais forte do que imagina! Cada dia é uma vitória, cada escolha é um passo em direção à sua melhor versão.
|
| 91 |
|
| 92 |
-
##
|
| 93 |
|
| 94 |
-
|
| 95 |
|
| 96 |
-
|
| 97 |
-
# Clone o repositório
|
| 98 |
-
git clone <seu-repositorio>
|
| 99 |
-
cd k
|
| 100 |
-
|
| 101 |
-
# Construa e inicie o container
|
| 102 |
-
docker-compose up -d
|
| 103 |
|
| 104 |
-
|
| 105 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
|
| 107 |
-
###
|
| 108 |
|
| 109 |
```bash
|
| 110 |
# Build da imagem
|
| 111 |
docker build -t fitness-app .
|
| 112 |
|
| 113 |
# Execute o container
|
| 114 |
-
docker run -
|
| 115 |
-
--name fitness-app \
|
| 116 |
-
-p 7860:7860 \
|
| 117 |
-
--restart unless-stopped \
|
| 118 |
-
fitness-app
|
| 119 |
|
| 120 |
# Acesse em: http://localhost:7860
|
| 121 |
```
|
| 122 |
|
| 123 |
-
### Comandos Úteis
|
| 124 |
-
|
| 125 |
-
```bash
|
| 126 |
-
# Ver logs
|
| 127 |
-
docker-compose logs -f fitness-app
|
| 128 |
-
|
| 129 |
-
# Parar o container
|
| 130 |
-
docker-compose down
|
| 131 |
-
|
| 132 |
-
# Reconstruir após alterações
|
| 133 |
-
docker-compose up -d --build
|
| 134 |
-
|
| 135 |
-
# Ver status de saúde
|
| 136 |
-
docker ps
|
| 137 |
-
```
|
| 138 |
-
|
| 139 |
-
### Recursos do Container
|
| 140 |
-
|
| 141 |
-
- **CPU**: 1 core (limite), 0.5 core (reservado)
|
| 142 |
-
- **Memória**: 512MB (limite), 256MB (reservado)
|
| 143 |
-
- **Porta**: 7860
|
| 144 |
-
- **Health Check**: A cada 30s
|
| 145 |
-
|
| 146 |
## 💻 Desenvolvimento Local
|
| 147 |
|
| 148 |
### Pré-requisitos
|
|
@@ -170,9 +141,8 @@ npm start
|
|
| 170 |
|
| 171 |
- `npm start` - Inicia o servidor de produção
|
| 172 |
- `npm run dev` - Modo desenvolvimento com nodemon
|
| 173 |
-
- `npm run build` - Build de produção otimizado
|
| 174 |
-
- `npm run download` - Baixa vídeos e áudios do Hugging Face
|
| 175 |
-
- `npm run analyze` - Analisa o bundle
|
| 176 |
|
| 177 |
## 📊 Performance
|
| 178 |
|
|
|
|
| 89 |
|
| 90 |
Lembre-se: você é mais forte do que imagina! Cada dia é uma vitória, cada escolha é um passo em direção à sua melhor versão.
|
| 91 |
|
| 92 |
+
## 🚀 Deploy no Hugging Face Spaces
|
| 93 |
|
| 94 |
+
Este app está otimizado para rodar perfeitamente no Hugging Face Spaces!
|
| 95 |
|
| 96 |
+
### Como fazer deploy:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
|
| 98 |
+
1. **Fork ou clone** este repositório
|
| 99 |
+
2. **Vá para Hugging Face Spaces**: https://huggingface.co/spaces
|
| 100 |
+
3. **Crie um novo Space** com Docker SDK
|
| 101 |
+
4. **Envie os arquivos** ou conecte ao seu repositório GitHub
|
| 102 |
+
5. **Aguarde o build** (leva cerca de 2-3 minutos)
|
| 103 |
+
6. **Pronto!** Seu app estará disponível em `https://huggingface.co/spaces/SEU_USERNAME/SEU_SPACE`
|
| 104 |
|
| 105 |
+
### 🐳 Executando Localmente com Docker
|
| 106 |
|
| 107 |
```bash
|
| 108 |
# Build da imagem
|
| 109 |
docker build -t fitness-app .
|
| 110 |
|
| 111 |
# Execute o container
|
| 112 |
+
docker run -p 7860:7860 fitness-app
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
|
| 114 |
# Acesse em: http://localhost:7860
|
| 115 |
```
|
| 116 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
## 💻 Desenvolvimento Local
|
| 118 |
|
| 119 |
### Pré-requisitos
|
|
|
|
| 141 |
|
| 142 |
- `npm start` - Inicia o servidor de produção
|
| 143 |
- `npm run dev` - Modo desenvolvimento com nodemon
|
| 144 |
+
- `npm run build` - Build de produção otimizado (minify + gzip)
|
| 145 |
+
- `npm run download` - Baixa vídeos e áudios do Hugging Face (31 MB)
|
|
|
|
| 146 |
|
| 147 |
## 📊 Performance
|
| 148 |
|
dist/app.min.js
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dist/app.min.js.gz
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:60a022e9575d6ea813d87ef7f0e383d2a557b4105e2910f21440c719c8d00ab2
|
| 3 |
+
size 21089
|
dist/build-report.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
| 1 |
{
|
| 2 |
-
"buildDate": "2025-10-
|
| 3 |
"files": [
|
| 4 |
{
|
| 5 |
"name": "JavaScript",
|
| 6 |
-
"originalSize":
|
| 7 |
-
"minifiedSize":
|
| 8 |
-
"gzipSize":
|
| 9 |
"minSavings": "40.4%",
|
| 10 |
"gzipSavings": "85.8%"
|
| 11 |
},
|
|
@@ -19,11 +19,11 @@
|
|
| 19 |
},
|
| 20 |
{
|
| 21 |
"name": "HTML",
|
| 22 |
-
"originalSize":
|
| 23 |
-
"minifiedSize":
|
| 24 |
-
"gzipSize":
|
| 25 |
-
"minSavings": "45.
|
| 26 |
-
"gzipSavings": "
|
| 27 |
},
|
| 28 |
{
|
| 29 |
"name": "Service Worker",
|
|
@@ -35,14 +35,14 @@
|
|
| 35 |
}
|
| 36 |
],
|
| 37 |
"totals": {
|
| 38 |
-
"originalSize":
|
| 39 |
-
"minifiedSize":
|
| 40 |
-
"gzipSize":
|
| 41 |
"minSavings": "39.3%",
|
| 42 |
"gzipSavings": "86.3%"
|
| 43 |
},
|
| 44 |
"performance": {
|
| 45 |
-
"estimatedLoadTime3G": "0.
|
| 46 |
"estimatedLoadTime4G": "0.05s"
|
| 47 |
}
|
| 48 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"buildDate": "2025-10-16T17:00:29.398Z",
|
| 3 |
"files": [
|
| 4 |
{
|
| 5 |
"name": "JavaScript",
|
| 6 |
+
"originalSize": 148275,
|
| 7 |
+
"minifiedSize": 88353,
|
| 8 |
+
"gzipSize": 21089,
|
| 9 |
"minSavings": "40.4%",
|
| 10 |
"gzipSavings": "85.8%"
|
| 11 |
},
|
|
|
|
| 19 |
},
|
| 20 |
{
|
| 21 |
"name": "HTML",
|
| 22 |
+
"originalSize": 35787,
|
| 23 |
+
"minifiedSize": 19425,
|
| 24 |
+
"gzipSize": 4974,
|
| 25 |
+
"minSavings": "45.7%",
|
| 26 |
+
"gzipSavings": "86.1%"
|
| 27 |
},
|
| 28 |
{
|
| 29 |
"name": "Service Worker",
|
|
|
|
| 35 |
}
|
| 36 |
],
|
| 37 |
"totals": {
|
| 38 |
+
"originalSize": 249129,
|
| 39 |
+
"minifiedSize": 151148,
|
| 40 |
+
"gzipSize": 34066,
|
| 41 |
"minSavings": "39.3%",
|
| 42 |
"gzipSavings": "86.3%"
|
| 43 |
},
|
| 44 |
"performance": {
|
| 45 |
+
"estimatedLoadTime3G": "0.35s",
|
| 46 |
"estimatedLoadTime4G": "0.05s"
|
| 47 |
}
|
| 48 |
}
|
dist/index.html
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
<!DOCTYPE html><html lang=pt-BR><head><meta charset=UTF-8><meta name=viewport content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes, viewport-fit=cover"><meta name=mobile-web-app-capable content=yes><meta name=apple-mobile-web-app-capable content=yes><meta name=apple-mobile-web-app-title content="Fitness App"><title>✨ Sua Jornada de Transformação</title><link rel=dns-prefetch href="https://fonts.googleapis.com"><link rel=dns-prefetch href="https://fonts.gstatic.com"><link rel=dns-prefetch href="https://huggingface.co"><link rel=preconnect href="https://fonts.googleapis.com"><link rel=preconnect href="https://fonts.gstatic.com" crossorigin><link rel=preconnect href="https://huggingface.co"><link rel=preconnect href="https://cdn-lfs.huggingface.co" crossorigin><link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;800&family=Playfair+Display:wght@400;600;700&display=swap" rel=stylesheet media=print onload="this.media='all'"><noscript><link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;800&family=Playfair+Display:wght@400;600;700&display=swap" rel=stylesheet></noscript><link rel=preload href="styles.css" as=style><link rel=stylesheet href="styles.css"><link rel=modulepreload href="app.js"><link rel=modulepreload href="lazy-video.js"><link rel=manifest href="manifest.json"><meta name=description content="Seu aplicativo de transformação pessoal completo - exercícios, nutrição e bem-estar"><meta name=keywords content="fitness, treino, nutrição, bem-estar, yoga, meditação, saúde"><meta name=theme-color content="#FF6B9D" media="(prefers-color-scheme: light)"><meta name=theme-color content="#1a1a1a" media="(prefers-color-scheme: dark)"><meta name=apple-mobile-web-app-capable content=yes><meta name=apple-mobile-web-app-status-bar-style content=black-translucent><link rel=apple-touch-icon sizes=192x192 href="icons/icon-192x192.svg"><link rel=apple-touch-icon sizes=512x512 href="icons/icon-512x512.svg"><meta name=msapplication-TileColor content="#FF6B9D"><meta name=msapplication-config content=none><link rel=icon type="image/svg+xml" href="icons/icon.svg"><link rel=preload href="app.js" as=script><link rel=modulepreload href="app.js"></head><body><div class=welcome-screen id=welcomeScreen><div class=welcome-content><div class=welcome-logo><div class=logo-heart>💖</div><h1>Bem-vinda!</h1><p>Sua jornada de transformação começa aqui</p></div><button class=btn-start-journey id=startJourney>Começar Agora ✨</button></div></div><div class=app-container id=appContainer style="display: none;"><header class=top-bar><div class=user-info style="cursor: pointer;" id=userProfileClick><div class=avatar id=userAvatar>💝</div><div class=user-text><span class=greeting id=greeting>Olá, Guerreira!</span><span class=streak>🔥 <span id=streakDays>0</span> dias seguidos</span></div></div><div class=top-actions><button class=icon-btn id=notifBtn title="Notificações"><span>🔔</span><span class=notification-badge id=notificationBadge style="display: none;">0</span></button></div></header><main class=main-view><section class="view active" id=homeView><div class=hero-section><h2 class=page-title>Sua Transformação</h2><div class=daily-progress><div class=progress-circle id=progressCircle><svg viewBox="0 0 120 120"><circle cx=60 cy=60 r=54 class=progress-bg></circle><circle cx=60 cy=60 r=54 class=progress-fill id=progressFill style="--progress: 0"></circle></svg><div class=progress-text><span class=progress-value id=progressValue>0</span>% <span class=progress-label>Hoje</span></div></div><div class=today-stats><div class=stat><span class=stat-icon>🔥</span><div><span class=stat-value id=caloriesBurned>0</span><span class=stat-label>kcal</span></div></div><div class=stat><span class=stat-icon>⏱️</span><div><span class=stat-value id=minutesActive>0</span><span class=stat-label>min</span></div></div><div class=stat><span class=stat-icon>💪</span><div><span class=stat-value id=workoutsCompleted>0</span><span class=stat-label>treinos</span></div></div></div></div></div><div class=plan-summary id=planSummary style="display: none;"><div class=plan-card><div class=plan-header><h3>🎯 Seu Plano Personalizado</h3><button class=btn-view-plan id=viewFullPlan>Ver Detalhes</button></div><div class=plan-quick-stats><div class=plan-stat><span class=plan-label>Meta</span><span class=plan-value id=planGoal>-</span></div><div class=plan-stat><span class=plan-label>Calorias/dia</span><span class=plan-value id=planCalories>-</span></div><div class=plan-stat><span class=plan-label>Treino</span><span class=plan-value id=planWorkout>-</span></div></div><div class=coach-message id=coachMessage> 💪 Continue assim! Você está no caminho certo! </div></div></div><div class=quick-actions><h3 class=section-title>Comece Agora</h3><div class=action-cards><div class=action-card data-navigate="workouts"><div class=action-icon>💪</div><h4>Treinar</h4><p>Escolha sua área</p></div><div class=action-card data-navigate="nutrition"><div class=action-icon>🥗</div><h4>Nutrição</h4><p>Acompanhe sua dieta</p></div><div class=action-card data-navigate="wellness"><div class=action-icon>🧘♀️</div><h4>Bem-Estar</h4><p>Massagens & Postura</p></div><div class=action-card data-navigate="progress"><div class=action-icon>📈</div><h4>Progresso</h4><p>Veja sua evolução</p></div></div></div><div class=motivation-card><div class=motivation-icon>✨</div><p class=motivation-text id=dailyMotivation>Você é capaz de coisas incríveis! Continue brilhando! 💫</p></div></section><section class=view id=workoutsView><div class=view-header><button class=btn-back data-back="home">← Voltar</button><h2 class=view-title>Escolha a Área</h2></div><div class=category-grid><div class=category-card data-category="personalized" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white;"><div class=category-image>🎯</div><h3>Personalizado</h3><p>Seu treino único</p><span class=category-badge style="background: rgba(255,255,255,0.3);">14 exercícios</span></div><div class=category-card data-category="abs"><div class=category-image>🔥</div><h3>Abdômen</h3><p>Barriga definida</p><span class=category-badge>5 exercícios</span></div><div class=category-card data-category="legs"><div class=category-image>🦵</div><h3>Pernas</h3><p>Pernas torneadas</p><span class=category-badge>15 exercícios</span></div><div class=category-card data-category="glutes"><div class=category-image>🍑</div><h3>Glúteos</h3><p>Bumbum empinado</p><span class=category-badge>14 exercícios</span></div><div class=category-card data-category="arms"><div class=category-image>💪</div><h3>Braços</h3><p>Braços definidos</p><span class=category-badge>10 exercícios</span></div><div class=category-card data-category="waist"><div class=category-image>⏳</div><h3>Cintura</h3><p>Cintura fina</p><span class=category-badge>8 exercícios</span></div><div class=category-card data-category="back"><div class=category-image>🏋️♀️</div><h3>Costas</h3><p>Postura correta</p><span class=category-badge>9 exercícios</span></div><div class=category-card data-category="cardio"><div class=category-image>❤️</div><h3>Cardio</h3><p>Queime calorias</p><span class=category-badge>11 exercícios</span></div><div class=category-card data-category="fullbody"><div class=category-image>✨</div><h3>Corpo Todo</h3><p>Treino completo</p><span class=category-badge>20 exercícios</span></div><div class=category-card data-category="yoga"><div class=category-image>🧘♀️</div><h3>Yoga</h3><p>Flexibilidade e paz</p><span class=category-badge>12 posições</span></div><div class=category-card data-category="massage"><div class=category-image>💆♀️</div><h3>Massagem</h3><p>Relaxamento total</p><span class=category-badge>8 técnicas</span></div><div class=category-card data-category="face"><div class=category-image>😊</div><h3>Rosto</h3><p>Rejuvenescimento facial</p><span class=category-badge>4 exercícios</span></div></div></section><section class=view id=exercisesListView><div class=view-header><button class=btn-back data-back="workouts">← Voltar</button><h2 class=view-title id=categoryTitle>Exercícios</h2></div><div class=exercises-container id=exercisesList></div></section><section class=view id=workoutSessionView><div class=workout-header><button class=btn-close-workout id=closeWorkout>✕</button><div class=workout-timer id=workoutTimer>00:00</div></div><div class=workout-content><div class=exercise-display><div class=exercise-name id=currentExerciseName>Preparando...</div><div class=exercise-count id=exerciseCount>Exercício 1 de 5</div><div class=exercise-demo id=exerciseDemo><div class=demo-placeholder><video class=demo-video id=demoVideo loop muted playsinline style="display: none;"><source src="" type="video/mp4"></video><span class=demo-icon id=demoIcon>💪</span></div></div><div class=exercise-instructions><div class=reps-info id=repsInfo>3 séries × 15 repetições</div><div class=rest-info id=restInfo>Descanso: 30s entre séries</div></div><div class=series-tracker id=seriesTracker><div class="series-dot completed"></div><div class=series-dot></div><div class=series-dot></div></div></div><div class=workout-controls><button class="btn-workout-action secondary" id=skipExercise>Pular</button><button class="btn-workout-action primary" id=completeExercise>Concluir Série</button></div></div><div class=workout-progress-bar><div class=progress-bar-fill id=workoutProgressBar style="width: 0%"></div></div></section><section class=view id=wellnessView><div class=view-header><button class=btn-back data-back="home">← Voltar</button><h2 class=view-title>Bem-Estar</h2></div><div class=wellness-grid><div class=wellness-card data-wellness="face-massage"><div class=wellness-icon>💆♀️</div><h3>Massagem Facial</h3><p>Rejuvenesça e relaxe</p><span class=duration>10 min</span></div><div class=wellness-card data-wellness="body-massage"><div class=wellness-icon>💫</div><h3>Massagem Corporal</h3><p>Alivie tensões</p><span class=duration>15 min</span></div><div class=wellness-card data-wellness="posture"><div class=wellness-icon>🧍♀️</div><h3>Correção Postural</h3><p>Melhore sua postura</p><span class=duration>12 min</span></div><div class=wellness-card data-wellness="stretching"><div class=wellness-icon>🤸♀️</div><h3>Alongamento</h3><p>Flexibilidade total</p><span class=duration>8 min</span></div><div class=wellness-card data-wellness="breathing"><div class=wellness-icon>🌬️</div><h3>Respiração</h3><p>Acalme sua mente</p><span class=duration>5 min</span></div><div class=wellness-card data-wellness="meditation"><div class=wellness-icon>🧘♀️</div><h3>Meditação</h3><p>Paz interior</p><span class=duration>10 min</span></div></div></section><section class=view id=nutritionView><div class=view-header><button class=btn-back data-back="home">← Voltar</button><h2 class=view-title>Nutrição</h2></div><div class=nutrition-summary><h3>Resumo de Hoje</h3><div class=macros-display><div class=macro-item><div class="macro-circle carbs"><span id=carbsValue>0g</span></div><span class=macro-label>Carboidratos</span></div><div class=macro-item><div class="macro-circle protein"><span id=proteinValue>0g</span></div><span class=macro-label>Proteínas</span></div><div class=macro-item><div class="macro-circle fat"><span id=fatValue>0g</span></div><span class=macro-label>Gorduras</span></div></div><div class=calories-total><span class=calories-value id=totalCalories>0</span><span class=calories-label>kcal hoje</span></div></div><div class=water-tracker><h3>Hidratação 💧</h3><div class=water-glasses><div class=glass data-glass="1">💧</div><div class=glass data-glass="2">💧</div><div class=glass data-glass="3">💧</div><div class=glass data-glass="4">💧</div><div class=glass data-glass="5">💧</div><div class=glass data-glass="6">💧</div><div class=glass data-glass="7">💧</div><div class=glass data-glass="8">💧</div></div><p class=water-goal><span id=waterCount>0</span>/8 copos (2L)</p></div></section><section class=view id=progressView><div class=view-header><button class=btn-back data-back="home">← Voltar</button><h2 class=view-title>Seu Progresso</h2></div><div class=weight-tracking-section><h3>Controle de Peso ⚖️</h3><div class=weight-card><div class=weight-current><div class=weight-label>Peso Atual</div><div class=weight-value id=currentWeight>--</div><button class=btn-update-weight id=updateWeightBtn>Atualizar Peso</button></div><div class=weight-stats><div class=weight-stat><div class=weight-stat-label>Peso Inicial</div><div class=weight-stat-value id=initialWeight>--</div></div><div class="weight-stat success"><div class=weight-stat-label>Perdeu</div><div class=weight-stat-value id=weightLost>0 kg</div></div><div class=weight-stat><div class=weight-stat-label>Meta</div><div class=weight-stat-value id=goalWeight>--</div></div></div><div class=weight-progress-bar><div class=weight-progress-fill id=weightProgressFill style="width: 0%"></div></div><div class=weight-chart-mini id=weightChartMini></div></div></div><div class=weekly-activity-section><h3>Atividade Semanal 📅</h3><div class=weekly-activity-grid id=weeklyActivityGrid></div></div><div class=detailed-stats-section><h3>Estatísticas Detalhadas 📊</h3><div class=stats-grid><div class=stat-detail-card><div class=stat-detail-icon>🔥</div><div class=stat-detail-content><div class=stat-detail-number id=totalWorkouts>0</div><div class=stat-detail-label>Treinos Completos</div><div class=stat-detail-sublabel><span id=thisWeekWorkouts>0</span> esta semana </div></div></div><div class=stat-detail-card><div class=stat-detail-icon>⏱️</div><div class=stat-detail-content><div class=stat-detail-number id=totalMinutes>0</div><div class=stat-detail-label>Minutos Ativos</div><div class=stat-detail-sublabel><span id=avgMinutes>0</span> min/treino </div></div></div><div class=stat-detail-card><div class=stat-detail-icon>🔥</div><div class=stat-detail-content><div class=stat-detail-number id=totalCaloriesDetail>0</div><div class=stat-detail-label>Calorias Queimadas</div><div class=stat-detail-sublabel><span id=avgCalories>0</span> kcal/treino </div></div></div><div class=stat-detail-card><div class=stat-detail-icon>📅</div><div class=stat-detail-content><div class=stat-detail-number id=daysActiveDetail>0</div><div class=stat-detail-label>Dias Ativos</div><div class=stat-detail-sublabel> Sequência: <span id=currentStreak>0</span> dias </div></div></div><div class=stat-detail-card><div class=stat-detail-icon>💧</div><div class=stat-detail-content><div class=stat-detail-number id=totalWaterGlasses>0</div><div class=stat-detail-label>Copos de Água</div><div class=stat-detail-sublabel><span id=waterStreak>0</span> dias 8 copos </div></div></div><div class=stat-detail-card><div class=stat-detail-icon>🏆</div><div class=stat-detail-content><div class=stat-detail-number id=achievementsUnlocked>0</div><div class=stat-detail-label>Conquistas</div><div class=stat-detail-sublabel> de <span id=totalAchievements>12</span> possíveis </div></div></div></div></div><div class=activity-chart-section><h3>Atividade Semanal 📈</h3><div class=weekly-chart><div class=chart-bars id=weeklyChart></div></div></div><div class=achievements-section><h3>Conquistas 🏆</h3><div class=achievements-grid id=achievementsGrid></div></div><div class=records-section><h3>Recordes Pessoais 🌟</h3><div class=records-list><div class=record-item><div class=record-icon>🔥</div><div class=record-content><div class=record-label>Maior Sequência</div><div class=record-value id=longestStreak>0 dias</div></div></div><div class=record-item><div class=record-icon>⏱️</div><div class=record-content><div class=record-label>Treino Mais Longo</div><div class=record-value id=longestWorkout>0 min</div></div></div><div class=record-item><div class=record-icon>💪</div><div class=record-content><div class=record-label>Categoria Favorita</div><div class=record-value id=favoriteCategory>--</div></div></div><div class=record-item><div class=record-icon>📅</div><div class=record-content><div class=record-label>Membro Desde</div><div class=record-value id=memberSince>--</div></div></div></div></div></section></main><nav class=bottom-nav><button class="nav-item active" data-nav="home"><span class=nav-icon>🏠</span><span class=nav-label>Início</span></button><button class=nav-item data-nav="workouts"><span class=nav-icon>💪</span><span class=nav-label>Treinar</span></button><button class=nav-item data-nav="nutrition"><span class=nav-icon>🥗</span><span class=nav-label>Nutrição</span></button><button class=nav-item data-nav="progress"><span class=nav-icon>📊</span><span class=nav-label>Progresso</span></button></nav></div><div class=modal id=completionModal><div class="modal-content celebration"><div class=celebration-confetti>🎉</div><h2 class=modal-title>Parabéns! 🎊</h2><p class=modal-message id=completionMessage>Você completou o treino!</p><div class=workout-summary id=workoutSummary><div class=summary-stat><span class=summary-icon>⏱️</span><span class=summary-value id=summaryTime>15 min</span></div><div class=summary-stat><span class=summary-icon>🔥</span><span class=summary-value id=summaryCalories>120 kcal</span></div><div class=summary-stat><span class=summary-icon>💪</span><span class=summary-value id=summaryExercises>8 exercícios</span></div></div><div class=workout-details id=workoutDetails style="margin-top: var(--spacing-md); padding: var(--spacing-md); background: var(--bg-light); border-radius: var(--radius-md); text-align: left; font-size: 0.9rem; color: var(--text-secondary);"></div><button class=btn-modal-primary id=closeCompletionModal>Continuar ✨</button></div></div><div class=modal id=weightModal><div class=modal-content><h2 class=modal-title>Atualizar Peso ⚖️</h2><div class=weight-input-group><label for=weightInput>Seu peso atual (kg)</label><input type=number id=weightInput step="0.1" min=30 max=200 placeholder="Ex: 65.5"></div><div class=weight-input-group><label for=goalWeightInput>Seu peso meta (kg)</label><input type=number id=goalWeightInput step="0.1" min=30 max=200 placeholder="Ex: 60.0"></div><div class=modal-actions><button class=btn-modal-secondary id=cancelWeightBtn>Cancelar</button><button class=btn-modal-primary id=saveWeightBtn>Salvar 💖</button></div></div></div><div class=settings-fab id=settingsFab><button class=fab-settings id=toggleSound><span class=fab-icon id=soundIcon>🔊</span></button></div><link rel=preload href="lazy-video.js" as=script><script src="lazy-video.js" defer></script><script> // Only load performance monitor in dev mode if (location.hostname === 'localhost' || location.search.includes('debug=true')) { const script = document.createElement('script'); script.src = 'performance-monitor.js'; script.defer = true; document.head.appendChild(script); } </script><div class=modal id=planModal><div class="modal-content plan-modal-content"><button class=modal-close onclick="app.closeModal('planModal')">×</button><div id=planModalContent><h2 class=modal-title>🎯 Seu Plano Completo</h2><div class=profile-info id=profileInfo></div><div class=plan-section><h3>🍽️ Plano Nutricional</h3><div id=nutritionPlan></div></div><div class=plan-section><h3>💪 Plano de Treino</h3><div id=workoutPlan></div></div><div class=plan-section><h3>📅 Linha do Tempo</h3><div id=timelinePlan></div></div><div class=plan-section><h3>💡 Dicas Personalizadas</h3><div id=tipsPlan></div></div><button class=btn-edit-profile id=editProfile>✏️ Editar Perfil</button></div></div></div><script src="app.js" defer></script></body></html>
|
|
|
|
| 1 |
+
<!DOCTYPE html><html lang=pt-BR><head><meta charset=UTF-8><meta name=viewport content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes, viewport-fit=cover"><meta name=mobile-web-app-capable content=yes><meta name=apple-mobile-web-app-capable content=yes><meta name=apple-mobile-web-app-title content="Fitness App"><title>✨ Sua Jornada de Transformação</title><link rel=dns-prefetch href="https://fonts.googleapis.com"><link rel=dns-prefetch href="https://fonts.gstatic.com"><link rel=dns-prefetch href="https://huggingface.co"><link rel=preconnect href="https://fonts.googleapis.com"><link rel=preconnect href="https://fonts.gstatic.com" crossorigin><link rel=preconnect href="https://huggingface.co"><link rel=preconnect href="https://cdn-lfs.huggingface.co" crossorigin><link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;800&family=Playfair+Display:wght@400;600;700&display=swap" rel=stylesheet media=print onload="this.media='all'"><noscript><link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;800&family=Playfair+Display:wght@400;600;700&display=swap" rel=stylesheet></noscript><link rel=preload href="styles.css" as=style><link rel=stylesheet href="styles.css"><link rel=modulepreload href="app.js"><link rel=manifest href="manifest.json"><meta name=description content="Seu aplicativo de transformação pessoal completo - exercícios, nutrição e bem-estar"><meta name=keywords content="fitness, treino, nutrição, bem-estar, yoga, meditação, saúde"><meta name=theme-color content="#FF6B9D" media="(prefers-color-scheme: light)"><meta name=theme-color content="#1a1a1a" media="(prefers-color-scheme: dark)"><meta name=apple-mobile-web-app-capable content=yes><meta name=apple-mobile-web-app-status-bar-style content=black-translucent><link rel=apple-touch-icon sizes=192x192 href="icons/icon-192x192.svg"><link rel=apple-touch-icon sizes=512x512 href="icons/icon-512x512.svg"><meta name=msapplication-TileColor content="#FF6B9D"><meta name=msapplication-config content=none><link rel=icon type="image/svg+xml" href="icons/icon.svg"><link rel=preload href="app.js" as=script><link rel=modulepreload href="app.js"></head><body><div class=welcome-screen id=welcomeScreen><div class=welcome-content><div class=welcome-logo><div class=logo-heart>💖</div><h1>Bem-vinda!</h1><p>Sua jornada de transformação começa aqui</p></div><button class=btn-start-journey id=startJourney>Começar Agora ✨</button></div></div><div class=app-container id=appContainer style="display: none;"><header class=top-bar><div class=user-info style="cursor: pointer;" id=userProfileClick><div class=avatar id=userAvatar>💝</div><div class=user-text><span class=greeting id=greeting>Olá, Guerreira!</span><span class=streak>🔥 <span id=streakDays>0</span> dias seguidos</span></div></div><div class=top-actions><button class=icon-btn id=notifBtn title="Notificações"><span>🔔</span><span class=notification-badge id=notificationBadge style="display: none;">0</span></button></div></header><main class=main-view><section class="view active" id=homeView><div class=hero-section><h2 class=page-title>Sua Transformação</h2><div class=daily-progress><div class=progress-circle id=progressCircle><svg viewBox="0 0 120 120"><circle cx=60 cy=60 r=54 class=progress-bg></circle><circle cx=60 cy=60 r=54 class=progress-fill id=progressFill style="--progress: 0"></circle></svg><div class=progress-text><span class=progress-value id=progressValue>0</span>% <span class=progress-label>Hoje</span></div></div><div class=today-stats><div class=stat><span class=stat-icon>🔥</span><div><span class=stat-value id=caloriesBurned>0</span><span class=stat-label>kcal</span></div></div><div class=stat><span class=stat-icon>⏱️</span><div><span class=stat-value id=minutesActive>0</span><span class=stat-label>min</span></div></div><div class=stat><span class=stat-icon>💪</span><div><span class=stat-value id=workoutsCompleted>0</span><span class=stat-label>treinos</span></div></div></div></div></div><div class=plan-summary id=planSummary style="display: none;"><div class=plan-card><div class=plan-header><h3>🎯 Seu Plano Personalizado</h3><button class=btn-view-plan id=viewFullPlan>Ver Detalhes</button></div><div class=plan-quick-stats><div class=plan-stat><span class=plan-label>Meta</span><span class=plan-value id=planGoal>-</span></div><div class=plan-stat><span class=plan-label>Calorias/dia</span><span class=plan-value id=planCalories>-</span></div><div class=plan-stat><span class=plan-label>Treino</span><span class=plan-value id=planWorkout>-</span></div></div><div class=coach-message id=coachMessage> 💪 Continue assim! Você está no caminho certo! </div></div></div><div class=quick-actions><h3 class=section-title>Comece Agora</h3><div class=action-cards><div class=action-card data-navigate="workouts"><div class=action-icon>💪</div><h4>Treinar</h4><p>Escolha sua área</p></div><div class=action-card data-navigate="nutrition"><div class=action-icon>🥗</div><h4>Nutrição</h4><p>Acompanhe sua dieta</p></div><div class=action-card data-navigate="wellness"><div class=action-icon>🧘♀️</div><h4>Bem-Estar</h4><p>Massagens & Postura</p></div><div class=action-card data-navigate="progress"><div class=action-icon>📈</div><h4>Progresso</h4><p>Veja sua evolução</p></div></div></div><div class=motivation-card><div class=motivation-icon>✨</div><p class=motivation-text id=dailyMotivation>Você é capaz de coisas incríveis! Continue brilhando! 💫</p></div></section><section class=view id=workoutsView><div class=view-header><button class=btn-back data-back="home">← Voltar</button><h2 class=view-title>Escolha a Área</h2></div><div class=category-grid><div class=category-card data-category="personalized" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white;"><div class=category-image>🎯</div><h3>Personalizado</h3><p>Seu treino único</p><span class=category-badge style="background: rgba(255,255,255,0.3);">14 exercícios</span></div><div class=category-card data-category="abs"><div class=category-image>🔥</div><h3>Abdômen</h3><p>Barriga definida</p><span class=category-badge>5 exercícios</span></div><div class=category-card data-category="legs"><div class=category-image>🦵</div><h3>Pernas</h3><p>Pernas torneadas</p><span class=category-badge>15 exercícios</span></div><div class=category-card data-category="glutes"><div class=category-image>🍑</div><h3>Glúteos</h3><p>Bumbum empinado</p><span class=category-badge>14 exercícios</span></div><div class=category-card data-category="arms"><div class=category-image>💪</div><h3>Braços</h3><p>Braços definidos</p><span class=category-badge>10 exercícios</span></div><div class=category-card data-category="waist"><div class=category-image>⏳</div><h3>Cintura</h3><p>Cintura fina</p><span class=category-badge>8 exercícios</span></div><div class=category-card data-category="back"><div class=category-image>🏋️♀️</div><h3>Costas</h3><p>Postura correta</p><span class=category-badge>9 exercícios</span></div><div class=category-card data-category="cardio"><div class=category-image>❤️</div><h3>Cardio</h3><p>Queime calorias</p><span class=category-badge>11 exercícios</span></div><div class=category-card data-category="fullbody"><div class=category-image>✨</div><h3>Corpo Todo</h3><p>Treino completo</p><span class=category-badge>20 exercícios</span></div><div class=category-card data-category="yoga"><div class=category-image>🧘♀️</div><h3>Yoga</h3><p>Flexibilidade e paz</p><span class=category-badge>12 posições</span></div><div class=category-card data-category="massage"><div class=category-image>💆♀️</div><h3>Massagem</h3><p>Relaxamento total</p><span class=category-badge>8 técnicas</span></div><div class=category-card data-category="face"><div class=category-image>😊</div><h3>Rosto</h3><p>Rejuvenescimento facial</p><span class=category-badge>4 exercícios</span></div></div></section><section class=view id=exercisesListView><div class=view-header><button class=btn-back data-back="workouts">← Voltar</button><h2 class=view-title id=categoryTitle>Exercícios</h2></div><div class=exercises-container id=exercisesList></div></section><section class=view id=workoutSessionView><div class=workout-header><button class=btn-close-workout id=closeWorkout>✕</button><div class=workout-timer id=workoutTimer>00:00</div></div><div class=workout-content><div class=exercise-display><div class=exercise-name id=currentExerciseName>Preparando...</div><div class=exercise-count id=exerciseCount>Exercício 1 de 5</div><div class=exercise-demo id=exerciseDemo><div class=demo-placeholder><video class=demo-video id=demoVideo loop muted playsinline style="display: none;"><source src="" type="video/mp4"></video><span class=demo-icon id=demoIcon>💪</span></div></div><div class=exercise-instructions><div class=reps-info id=repsInfo>3 séries × 15 repetições</div><div class=rest-info id=restInfo>Descanso: 30s entre séries</div></div><div class=series-tracker id=seriesTracker><div class="series-dot completed"></div><div class=series-dot></div><div class=series-dot></div></div></div><div class=workout-controls><button class="btn-workout-action secondary" id=skipExercise>Pular</button><button class="btn-workout-action primary" id=completeExercise>Concluir Série</button></div></div><div class=workout-progress-bar><div class=progress-bar-fill id=workoutProgressBar style="width: 0%"></div></div></section><section class=view id=wellnessView><div class=view-header><button class=btn-back data-back="home">← Voltar</button><h2 class=view-title>Bem-Estar</h2></div><div class=wellness-grid><div class=wellness-card data-wellness="face-massage"><div class=wellness-icon>💆♀️</div><h3>Massagem Facial</h3><p>Rejuvenesça e relaxe</p><span class=duration>10 min</span></div><div class=wellness-card data-wellness="body-massage"><div class=wellness-icon>💫</div><h3>Massagem Corporal</h3><p>Alivie tensões</p><span class=duration>15 min</span></div><div class=wellness-card data-wellness="posture"><div class=wellness-icon>🧍♀️</div><h3>Correção Postural</h3><p>Melhore sua postura</p><span class=duration>12 min</span></div><div class=wellness-card data-wellness="stretching"><div class=wellness-icon>🤸♀️</div><h3>Alongamento</h3><p>Flexibilidade total</p><span class=duration>8 min</span></div><div class=wellness-card data-wellness="breathing"><div class=wellness-icon>🌬️</div><h3>Respiração</h3><p>Acalme sua mente</p><span class=duration>5 min</span></div><div class=wellness-card data-wellness="meditation"><div class=wellness-icon>🧘♀️</div><h3>Medita��ão</h3><p>Paz interior</p><span class=duration>10 min</span></div></div></section><section class=view id=nutritionView><div class=view-header><button class=btn-back data-back="home">← Voltar</button><h2 class=view-title>Nutrição</h2></div><div class=nutrition-summary><h3>Resumo de Hoje</h3><div class=macros-display><div class=macro-item><div class="macro-circle carbs"><span id=carbsValue>0g</span></div><span class=macro-label>Carboidratos</span></div><div class=macro-item><div class="macro-circle protein"><span id=proteinValue>0g</span></div><span class=macro-label>Proteínas</span></div><div class=macro-item><div class="macro-circle fat"><span id=fatValue>0g</span></div><span class=macro-label>Gorduras</span></div></div><div class=calories-total><span class=calories-value id=totalCalories>0</span><span class=calories-label>kcal hoje</span></div></div><div class=water-tracker><h3>Hidratação 💧</h3><div class=water-glasses><div class=glass data-glass="1">💧</div><div class=glass data-glass="2">💧</div><div class=glass data-glass="3">💧</div><div class=glass data-glass="4">💧</div><div class=glass data-glass="5">💧</div><div class=glass data-glass="6">💧</div><div class=glass data-glass="7">💧</div><div class=glass data-glass="8">💧</div></div><p class=water-goal><span id=waterCount>0</span>/8 copos (2L)</p></div></section><section class=view id=progressView><div class=view-header><button class=btn-back data-back="home">← Voltar</button><h2 class=view-title>Seu Progresso</h2></div><div class=weight-tracking-section><h3>Controle de Peso ⚖️</h3><div class=weight-card><div class=weight-current><div class=weight-label>Peso Atual</div><div class=weight-value id=currentWeight>--</div><button class=btn-update-weight id=updateWeightBtn>Atualizar Peso</button></div><div class=weight-stats><div class=weight-stat><div class=weight-stat-label>Peso Inicial</div><div class=weight-stat-value id=initialWeight>--</div></div><div class="weight-stat success"><div class=weight-stat-label>Perdeu</div><div class=weight-stat-value id=weightLost>0 kg</div></div><div class=weight-stat><div class=weight-stat-label>Meta</div><div class=weight-stat-value id=goalWeight>--</div></div></div><div class=weight-progress-bar><div class=weight-progress-fill id=weightProgressFill style="width: 0%"></div></div><div class=weight-chart-mini id=weightChartMini></div></div></div><div class=weekly-activity-section><h3>Atividade Semanal 📅</h3><div class=weekly-activity-grid id=weeklyActivityGrid></div></div><div class=detailed-stats-section><h3>Estatísticas Detalhadas 📊</h3><div class=stats-grid><div class=stat-detail-card><div class=stat-detail-icon>🔥</div><div class=stat-detail-content><div class=stat-detail-number id=totalWorkouts>0</div><div class=stat-detail-label>Treinos Completos</div><div class=stat-detail-sublabel><span id=thisWeekWorkouts>0</span> esta semana </div></div></div><div class=stat-detail-card><div class=stat-detail-icon>⏱️</div><div class=stat-detail-content><div class=stat-detail-number id=totalMinutes>0</div><div class=stat-detail-label>Minutos Ativos</div><div class=stat-detail-sublabel><span id=avgMinutes>0</span> min/treino </div></div></div><div class=stat-detail-card><div class=stat-detail-icon>🔥</div><div class=stat-detail-content><div class=stat-detail-number id=totalCaloriesDetail>0</div><div class=stat-detail-label>Calorias Queimadas</div><div class=stat-detail-sublabel><span id=avgCalories>0</span> kcal/treino </div></div></div><div class=stat-detail-card><div class=stat-detail-icon>📅</div><div class=stat-detail-content><div class=stat-detail-number id=daysActiveDetail>0</div><div class=stat-detail-label>Dias Ativos</div><div class=stat-detail-sublabel> Sequência: <span id=currentStreak>0</span> dias </div></div></div><div class=stat-detail-card><div class=stat-detail-icon>💧</div><div class=stat-detail-content><div class=stat-detail-number id=totalWaterGlasses>0</div><div class=stat-detail-label>Copos de Água</div><div class=stat-detail-sublabel><span id=waterStreak>0</span> dias 8 copos </div></div></div><div class=stat-detail-card><div class=stat-detail-icon>🏆</div><div class=stat-detail-content><div class=stat-detail-number id=achievementsUnlocked>0</div><div class=stat-detail-label>Conquistas</div><div class=stat-detail-sublabel> de <span id=totalAchievements>12</span> possíveis </div></div></div></div></div><div class=activity-chart-section><h3>Atividade Semanal 📈</h3><div class=weekly-chart><div class=chart-bars id=weeklyChart></div></div></div><div class=achievements-section><h3>Conquistas 🏆</h3><div class=achievements-grid id=achievementsGrid></div></div><div class=records-section><h3>Recordes Pessoais 🌟</h3><div class=records-list><div class=record-item><div class=record-icon>🔥</div><div class=record-content><div class=record-label>Maior Sequência</div><div class=record-value id=longestStreak>0 dias</div></div></div><div class=record-item><div class=record-icon>⏱️</div><div class=record-content><div class=record-label>Treino Mais Longo</div><div class=record-value id=longestWorkout>0 min</div></div></div><div class=record-item><div class=record-icon>💪</div><div class=record-content><div class=record-label>Categoria Favorita</div><div class=record-value id=favoriteCategory>--</div></div></div><div class=record-item><div class=record-icon>📅</div><div class=record-content><div class=record-label>Membro Desde</div><div class=record-value id=memberSince>--</div></div></div></div></div></section></main><nav class=bottom-nav><button class="nav-item active" data-nav="home"><span class=nav-icon>🏠</span><span class=nav-label>Início</span></button><button class=nav-item data-nav="workouts"><span class=nav-icon>💪</span><span class=nav-label>Treinar</span></button><button class=nav-item data-nav="nutrition"><span class=nav-icon>🥗</span><span class=nav-label>Nutrição</span></button><button class=nav-item data-nav="progress"><span class=nav-icon>📊</span><span class=nav-label>Progresso</span></button></nav></div><div class=modal id=completionModal><div class="modal-content celebration"><div class=celebration-confetti>🎉</div><h2 class=modal-title>Parabéns! 🎊</h2><p class=modal-message id=completionMessage>Você completou o treino!</p><div class=workout-summary id=workoutSummary><div class=summary-stat><span class=summary-icon>⏱️</span><span class=summary-value id=summaryTime>15 min</span></div><div class=summary-stat><span class=summary-icon>🔥</span><span class=summary-value id=summaryCalories>120 kcal</span></div><div class=summary-stat><span class=summary-icon>💪</span><span class=summary-value id=summaryExercises>8 exercícios</span></div></div><div class=workout-details id=workoutDetails style="margin-top: var(--spacing-md); padding: var(--spacing-md); background: var(--bg-light); border-radius: var(--radius-md); text-align: left; font-size: 0.9rem; color: var(--text-secondary);"></div><button class=btn-modal-primary id=closeCompletionModal>Continuar ✨</button></div></div><div class=modal id=weightModal><div class=modal-content><h2 class=modal-title>Atualizar Peso ⚖️</h2><div class=weight-input-group><label for=weightInput>Seu peso atual (kg)</label><input type=number id=weightInput step="0.1" min=30 max=200 placeholder="Ex: 65.5"></div><div class=weight-input-group><label for=goalWeightInput>Seu peso meta (kg)</label><input type=number id=goalWeightInput step="0.1" min=30 max=200 placeholder="Ex: 60.0"></div><div class=modal-actions><button class=btn-modal-secondary id=cancelWeightBtn>Cancelar</button><button class=btn-modal-primary id=saveWeightBtn>Salvar 💖</button></div></div></div><div class=settings-fab id=settingsFab><button class=fab-settings id=toggleSound><span class=fab-icon id=soundIcon>🔊</span></button></div><div class=modal id=planModal><div class="modal-content plan-modal-content"><button class=modal-close id=closePlanModal>×</button><div id=planModalContent><h2 class=modal-title>🎯 Seu Plano Completo</h2><div class=profile-info id=profileInfo></div><div class=plan-section><h3>🍽️ Plano Nutricional</h3><div id=nutritionPlan></div></div><div class=plan-section><h3>💪 Plano de Treino</h3><div id=workoutPlan></div></div><div class=plan-section><h3>📅 Linha do Tempo</h3><div id=timelinePlan></div></div><div class=plan-section><h3>💡 Dicas Personalizadas</h3><div id=tipsPlan></div></div><button class=btn-edit-profile id=editProfile>✏️ Editar Perfil</button></div></div></div><script src="app.js" defer></script></body></html>
|
dist/index.html.gz
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d74faced93f2d5c51e169d69bb28612390c47c9693eb183af626dc43936ed35b
|
| 3 |
+
size 4974
|
docker-entrypoint.sh
CHANGED
|
@@ -2,42 +2,8 @@
|
|
| 2 |
set -e
|
| 3 |
|
| 4 |
echo "🚀 Starting Fitness App..."
|
| 5 |
-
|
| 6 |
-
# Check if videos directory exists and has files
|
| 7 |
-
if [ ! -d "/app/public/videos" ] || [ -z "$(ls -A /app/public/videos 2>/dev/null)" ]; then
|
| 8 |
-
echo "📥 Videos directory is empty, attempting to download..."
|
| 9 |
-
if npm run download 2>/dev/null; then
|
| 10 |
-
echo "✅ Videos downloaded successfully!"
|
| 11 |
-
else
|
| 12 |
-
echo "⚠️ Video download failed, app will use CDN fallback"
|
| 13 |
-
fi
|
| 14 |
-
else
|
| 15 |
-
VIDEO_COUNT=$(ls -1 /app/public/videos/*.mp4 2>/dev/null | wc -l)
|
| 16 |
-
echo "✅ Found $VIDEO_COUNT video files"
|
| 17 |
-
fi
|
| 18 |
-
|
| 19 |
-
# Check if audio directory exists and has files
|
| 20 |
-
if [ ! -d "/app/public/songs" ] || [ -z "$(ls -A /app/public/songs 2>/dev/null)" ]; then
|
| 21 |
-
echo "📥 Audio directory is empty"
|
| 22 |
-
echo "⚠️ Audio files missing, some features may not work"
|
| 23 |
-
else
|
| 24 |
-
AUDIO_COUNT=$(ls -1 /app/public/songs/*.{mp3,ogg} 2>/dev/null | wc -l)
|
| 25 |
-
echo "✅ Found $AUDIO_COUNT audio files"
|
| 26 |
-
fi
|
| 27 |
-
|
| 28 |
-
# Check if dist directory exists (production build)
|
| 29 |
-
if [ -d "/app/dist" ]; then
|
| 30 |
-
echo "✅ Production build found"
|
| 31 |
-
else
|
| 32 |
-
echo "⚠️ No production build found, using development files"
|
| 33 |
-
fi
|
| 34 |
-
|
| 35 |
-
# Print environment info
|
| 36 |
-
echo "📊 Environment: $NODE_ENV"
|
| 37 |
echo "🌐 Port: ${PORT:-7860}"
|
| 38 |
-
echo "👤 Running as: $(whoami)"
|
| 39 |
|
| 40 |
# Start the application
|
| 41 |
-
echo "🎯 Starting server..."
|
| 42 |
exec node server.js
|
| 43 |
-
|
|
|
|
| 2 |
set -e
|
| 3 |
|
| 4 |
echo "🚀 Starting Fitness App..."
|
| 5 |
+
echo "📊 Environment: ${NODE_ENV:-production}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
echo "🌐 Port: ${PORT:-7860}"
|
|
|
|
| 7 |
|
| 8 |
# Start the application
|
|
|
|
| 9 |
exec node server.js
|
|
|
package.json
CHANGED
|
@@ -7,13 +7,7 @@
|
|
| 7 |
"start": "node server.js",
|
| 8 |
"dev": "nodemon server.js",
|
| 9 |
"build": "node scripts/build-production.js",
|
| 10 |
-
"
|
| 11 |
-
"minify": "node scripts/minify.js",
|
| 12 |
-
"analyze": "node scripts/analyze-bundle.js",
|
| 13 |
-
"optimize": "node scripts/build-production.js && node scripts/optimize-images.js",
|
| 14 |
-
"download": "node scripts/download-videos.js",
|
| 15 |
-
"test": "echo 'No tests specified'",
|
| 16 |
-
"lighthouse": "lighthouse http://localhost:7860 --view --output html --output-path ./lighthouse-report.html"
|
| 17 |
},
|
| 18 |
"keywords": [
|
| 19 |
"ketogenic",
|
|
|
|
| 7 |
"start": "node server.js",
|
| 8 |
"dev": "nodemon server.js",
|
| 9 |
"build": "node scripts/build-production.js",
|
| 10 |
+
"download": "node scripts/download-videos.js"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
},
|
| 12 |
"keywords": [
|
| 13 |
"ketogenic",
|
public/app.js
CHANGED
|
@@ -1558,6 +1558,12 @@ class FitnessApp {
|
|
| 1558 |
}
|
| 1559 |
}
|
| 1560 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1561 |
if (e.target.id === 'notifBtn' || e.target.closest('#notifBtn')) {
|
| 1562 |
e.preventDefault();
|
| 1563 |
e.stopPropagation();
|
|
|
|
| 1558 |
}
|
| 1559 |
}
|
| 1560 |
|
| 1561 |
+
if (e.target.id === 'closePlanModal' || e.target.closest('#closePlanModal')) {
|
| 1562 |
+
e.preventDefault();
|
| 1563 |
+
e.stopPropagation();
|
| 1564 |
+
this.closeModal('planModal');
|
| 1565 |
+
}
|
| 1566 |
+
|
| 1567 |
if (e.target.id === 'notifBtn' || e.target.closest('#notifBtn')) {
|
| 1568 |
e.preventDefault();
|
| 1569 |
e.stopPropagation();
|
public/index.html
CHANGED
|
@@ -31,7 +31,6 @@
|
|
| 31 |
|
| 32 |
<!-- Performance: Preload critical JavaScript -->
|
| 33 |
<link rel="modulepreload" href="app.js">
|
| 34 |
-
<link rel="modulepreload" href="lazy-video.js">
|
| 35 |
|
| 36 |
<!-- PWA Manifest -->
|
| 37 |
<link rel="manifest" href="manifest.json">
|
|
@@ -690,27 +689,11 @@
|
|
| 690 |
</button>
|
| 691 |
</div>
|
| 692 |
|
| 693 |
-
<!-- Performance: Critical path optimization -->
|
| 694 |
-
<!-- Lazy video loading (high priority) -->
|
| 695 |
-
<link rel="preload" href="lazy-video.js" as="script">
|
| 696 |
-
<script src="lazy-video.js" defer></script>
|
| 697 |
-
|
| 698 |
-
<!-- Performance monitoring (development only) -->
|
| 699 |
-
<script>
|
| 700 |
-
// Only load performance monitor in dev mode
|
| 701 |
-
if (location.hostname === 'localhost' || location.search.includes('debug=true')) {
|
| 702 |
-
const script = document.createElement('script');
|
| 703 |
-
script.src = 'performance-monitor.js';
|
| 704 |
-
script.defer = true;
|
| 705 |
-
document.head.appendChild(script);
|
| 706 |
-
}
|
| 707 |
-
</script>
|
| 708 |
-
|
| 709 |
<!-- Performance: Defer non-critical JavaScript -->
|
| 710 |
<!-- Personal Plan Modal -->
|
| 711 |
<div class="modal" id="planModal">
|
| 712 |
<div class="modal-content plan-modal-content">
|
| 713 |
-
<button class="modal-close"
|
| 714 |
<div id="planModalContent">
|
| 715 |
<h2 class="modal-title">🎯 Seu Plano Completo</h2>
|
| 716 |
|
|
|
|
| 31 |
|
| 32 |
<!-- Performance: Preload critical JavaScript -->
|
| 33 |
<link rel="modulepreload" href="app.js">
|
|
|
|
| 34 |
|
| 35 |
<!-- PWA Manifest -->
|
| 36 |
<link rel="manifest" href="manifest.json">
|
|
|
|
| 689 |
</button>
|
| 690 |
</div>
|
| 691 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 692 |
<!-- Performance: Defer non-critical JavaScript -->
|
| 693 |
<!-- Personal Plan Modal -->
|
| 694 |
<div class="modal" id="planModal">
|
| 695 |
<div class="modal-content plan-modal-content">
|
| 696 |
+
<button class="modal-close" id="closePlanModal">×</button>
|
| 697 |
<div id="planModalContent">
|
| 698 |
<h2 class="modal-title">🎯 Seu Plano Completo</h2>
|
| 699 |
|