From 9e66744a5e390ce99466ea37dad112a770a194c7 Mon Sep 17 00:00:00 2001 From: Ricardo Campos Date: Mon, 16 Jun 2025 17:33:52 -0300 Subject: [PATCH] feat: add select item and improve settings --- auth.css | 38 +++++---- index.html | 35 ++++++-- src/appwrite.ts | 1 - src/foodDatabase.ts | 148 ++++++++++++++++---------------- src/index.ts | 202 +++++++++++++++++++++++++++++++++++++------- src/types.ts | 4 +- style.css | 173 +++++++++++++++++++++++++++++++------ 7 files changed, 445 insertions(+), 156 deletions(-) diff --git a/auth.css b/auth.css index 04db75a..ffce53c 100644 --- a/auth.css +++ b/auth.css @@ -2,9 +2,9 @@ .auth-header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; - padding: 15px 0; + padding: 12px 0; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); - position: sticky; + border-radius: 6px; top: 0; z-index: 1000; } @@ -12,15 +12,16 @@ .auth-container { max-width: 1200px; margin: 0 auto; - padding: 0 20px; + padding: 0 15px; display: flex; justify-content: space-between; align-items: center; + min-height: 50px; } .logo h2 { margin: 0; - font-size: 1.5rem; + font-size: 1.3rem; font-weight: 600; } @@ -32,7 +33,7 @@ .auth-form { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); - border-radius: 10px; + border-radius: 6px; padding: 25px; min-width: 300px; border: 1px solid rgba(255, 255, 255, 0.2); @@ -110,28 +111,28 @@ .user-info { display: flex; align-items: center; - gap: 15px; + gap: 10px; } .user-details { display: flex; align-items: center; - gap: 15px; + gap: 10px; } .user-details span { font-weight: 500; - font-size: 1rem; + font-size: 0.9rem; } .logout-btn { - padding: 8px 16px; + padding: 6px 12px; background: rgba(255, 255, 255, 0.2); color: white; border: 1px solid rgba(255, 255, 255, 0.3); border-radius: 6px; cursor: pointer; - font-size: 0.9rem; + font-size: 0.8rem; transition: all 0.3s ease; backdrop-filter: blur(10px); } @@ -198,15 +199,22 @@ /* Mobile Responsive for Auth */ @media (max-width: 768px) { + .auth-header { + padding: 10px 0; + } + .auth-container { - flex-direction: column; - gap: 15px; - padding: 0 15px; + min-height: 45px; + padding: 0 12px; } .logo { order: 1; } + + .logo h2 { + font-size: 1.1rem; + } .auth-section, .user-info { @@ -222,8 +230,6 @@ } .user-details { - flex-direction: column; - gap: 10px; - text-align: center; + gap: 8px; } } diff --git a/index.html b/index.html index d8f18b2..4eaaa65 100644 --- a/index.html +++ b/index.html @@ -78,8 +78,6 @@
-

🍎 Daily Calorie Tracker

-
@@ -89,35 +87,50 @@
+
Protein (g)
0
-
Protein (g)
+
Fat (g)
0
-
Fat (g)
+
Carbs (g)
0
-
Carbs (g)
+
Fiber (g)
0
-
Fiber (g)
+ + +

Add Food

- +
+ +
+ + +
+ +
+
@@ -198,15 +211,19 @@
+
+
+
+
diff --git a/src/appwrite.ts b/src/appwrite.ts index 7e7a7b1..d3a53b2 100644 --- a/src/appwrite.ts +++ b/src/appwrite.ts @@ -88,7 +88,6 @@ export class AppwriteDB { { ...entryData, userId: (await account.get()).$id, - createdAt: new Date().toISOString() } ); console.debug('Food entry saved:', response); diff --git a/src/foodDatabase.ts b/src/foodDatabase.ts index 1cfd960..6703e2d 100644 --- a/src/foodDatabase.ts +++ b/src/foodDatabase.ts @@ -1,79 +1,83 @@ import { FoodItem } from "./types"; export const foodDatabase: FoodItem[] = [ - { name: 'Frutas - Abacate', info: { calories: 96, protein: 1.2, fat: 8.4, carbs: 6, fiber: 6.3 } }, - { name: 'Frutas - Abacaxi', info: { calories: 48, protein: 0.9, fat: 0.1, carbs: 12.3, fiber: 1 } }, - { name: 'Frutas - Banana Nanica', info: { calories: 92, protein: 1.4, fat: 0.1, carbs: 23.8, fiber: 1.9 } }, - { name: 'Frutas - Laranja', info: { calories: 37, protein: 1, fat: 0.1, carbs: 8.9, fiber: 0.8 } }, - { name: 'Frutas - Maçã', info: { calories: 56, protein: 0.3, fat: 0, carbs: 15.2, fiber: 1.3 } }, - { name: 'Frutas - Manga Palmer', info: { calories: 72, protein: 0.4, fat: 0.2, carbs: 19.4, fiber: 1.6 } }, - { name: 'Frutas - Mamão', info: { calories: 40, protein: 0.5, fat: 0.1, carbs: 10.4, fiber: 1 } }, - { name: 'Frutas - Melancia', info: { calories: 33, protein: 0.9, fat: 0, carbs: 8.1, fiber: 0.1 } }, - { name: 'Frutas - Melão', info: { calories: 29, protein: 0.7, fat: 0, carbs: 7.5, fiber: 0.3 } }, - { name: 'Frutas - Uva', info: { calories: 53, protein: 0.7, fat: 0.2, carbs: 13.6, fiber: 0.9 } }, - - { name: 'Verduras - Agrião', info: { calories: 17, protein: 2.7, fat: 0.2, carbs: 2.3, fiber: 2.1 } }, - { name: 'Verduras - Espinafre', info: { calories: 16, protein: 2, fat: 0.2, carbs: 2.6, fiber: 2.1 } }, - { name: 'Verduras - Rúcula', info: { calories: 13, protein: 1.8, fat: 0.1, carbs: 2.2, fiber: 1.7 } }, + // Gorduras - Fats + { name: 'Abacate', info: { calories: 96, protein: 1.2, fat: 8.4, carbs: 6, fiber: 6.3, category: 'fats' } }, + { name: 'Amêndoas', info: { calories: 581, protein: 18.6, fat: 47.3, carbs: 29.5, fiber: 11.6, category: 'fats' } }, + { name: 'Amendoin natural', info: { calories: 611, protein: 26, fat: 49, carbs: 16, fiber: 8.5, category: 'fats' } }, + { name: 'Azeite de Oliva EV', info: { calories: 844, protein: 0, fat: 100, carbs: 0, fiber: 0, category: 'fats' } }, + { name: 'Castanha de Caju', info: { calories: 570, protein: 18.5, fat: 46.3, carbs: 29.1, fiber: 3.7, category: 'fats' } }, + { name: 'Castanha do Pará', info: { calories: 643, protein: 14.5, fat: 63.5, carbs: 15.1, fiber: 7.9, category: 'fats' } }, + { name: 'Semente de Chia', info: { calories: 490, protein: 15.6, fat: 30.7, carbs: 43.8, fiber: 37.7, category: 'fats' } }, + { name: 'Semente de Linhaça', info: { calories: 495, protein: 14.1, fat: 32.3, carbs: 43.3, fiber: 33.5, category: 'fats' } }, + { name: 'Semente de Gergelim', info: { calories: 584, protein: 21.2, fat: 50.4, carbs: 21.6, fiber: 11.9, category: 'fats' } }, + { name: 'Pasta de Amendoim Growth', info: { calories: 544, protein: 27, fat: 33, carbs: 20, fiber: 8, category: 'fats' } }, - { name: 'Legumes - Abóbora Cabotian (crua)', info: { calories: 39, protein: 1.7, fat: 0.5, carbs: 8.4, fiber: 2.2 } }, - { name: 'Legumes - Abóbora Cabotian (cozida)', info: { calories: 48, protein: 1.4, fat: 0.7, carbs: 10.8, fiber: 2.5 } }, - { name: 'Legumes - Brócolis (cozido)', info: { calories: 25, protein: 2.1, fat: 0.5, carbs: 4.4, fiber: 3.4 } }, - { name: 'Legumes - Cenoura (cozida)', info: { calories: 30, protein: 0.8, fat: 0.2, carbs: 6.7, fiber: 2.6 } }, - { name: 'Legumes - Couve flor (cozida)', info: { calories: 19, protein: 1.2, fat: 0.3, carbs: 3.9, fiber: 2.1 } }, - { name: 'Legumes - Pepino', info: { calories: 10, protein: 0.9, fat: 0, carbs: 2, fiber: 1.1 } }, - { name: 'Legumes - Tomate', info: { calories: 15, protein: 1.1, fat: 0.2, carbs: 3.1, fiber: 1.2 } }, - - { name: 'Algas - Spirulina', info: { calories: 290, protein: 57.5, fat: 23.9, carbs: 7.7, fiber: 0 } }, - - { name: 'Carboidratos - Batata doce (assada)', info: { calories: 90, protein: 2.0, fat: 0.1, carbs: 20.7, fiber: 3.3 } }, - { name: 'Carboidratos - Batata doce (cozida)', info: { calories: 77, protein: 0.6, fat: 0.1, carbs: 18.4, fiber: 2.2 } }, - { name: 'Carboidratos - Batata doce (crua)', info: { calories: 118, protein: 1.3, fat: 0.1, carbs: 28.2, fiber: 2.6 } }, - { name: 'Carboidratos - Batata inglesa (assada)', info: { calories: 94, protein: 2.1, fat: 0.1, carbs: 21.8, fiber: 2.1 } }, - { name: 'Carboidratos - Batata inglesa (cozida)', info: { calories: 52, protein: 1.2, fat: 0, carbs: 11.9, fiber: 1.3 } }, - { name: 'Carboidratos - Batata inglesa (crua)', info: { calories: 64, protein: 1.8, fat: 0, carbs: 14.7, fiber: 1.2 } }, - { name: 'Carboidratos - Mandioca (cozida)', info: { calories: 125, protein: 0.6, fat: 0.3, carbs: 30.1, fiber: 1.6 } }, - { name: 'Carboidratos - Pão Francês', info: { calories: 300, protein: 8, fat: 3.1, carbs: 58.6, fiber: 2.3 } }, - { name: 'Carboidrados - Polenta (cozida)', info: { calories: 192, protein: 4.8, fat: 1.2, carbs: 40, fiber: 3.8 } }, - - { name: 'Proteínas - Atum Sólido (natural)', info: { calories: 135, protein: 28.3, fat: 2.7, carbs: 0, fiber: 0 } }, - { name: 'Proteínas - Filé de Tilápia (cozido)', info: { calories: 128, protein: 26.1, fat: 2.6, carbs: 0, fiber: 0 } }, - { name: 'Proteínas - Ovo inteiro (cozido)', info: { calories: 146, protein: 13.3, fat: 9.5, carbs: 0.6, fiber: 0 } }, - { name: 'Proteínas - Ovo clara (cozido)', info: { calories: 59, protein: 13.4, fat: 0.1, carbs: 0, fiber: 0 } }, - { name: 'Proteínas - PTS (crua)', info: { calories: 288, protein: 52, fat: 0, carbs: 20, fiber: 14 } }, - { name: 'Proteínas - Patinho moído (grelhado)', info: { calories: 219, protein: 35.9, fat: 7.3, carbs: 0, fiber: 0 } }, - { name: 'Proteínas - Soja em Pó Growth', info: { calories: 400, protein: 86.7, fat: 5, carbs: 3.3, fiber: 0 } }, - { name: 'Proteínas - Sobrecoxa s/pele (cozida)', info: { calories: 245, protein: 24.9, fat: 15.4, carbs: 0, fiber: 0 } }, - { name: 'Proteínas - Tofu', info: { calories: 65, protein: 6.5, fat: 4, carbs: 2, fiber: 0.75 } }, - - { name: 'Grãos - Arroz integral (cozido)', info: { calories: 130, protein: 2.7, fat: 0.3, carbs: 28, fiber: 0.4 } }, - { name: 'Grãos - Aveia', info: { calories: 394, protein: 13.9, fat: 8.5, carbs: 66.6, fiber: 9.1 } }, - { name: 'Grãos - Ervilha (cozida)', info: { calories: 88, protein: 7.5, fat: 0.5, carbs: 14.2, fiber: 9.7 } }, - { name: 'Grãos - Feijão preto (cozido)', info: { calories: 77, protein: 4.5, fat: 0.5, carbs: 14, fiber: 8.4 } }, - { name: 'Grãos - Lentilha (cozida)', info: { calories: 93, protein: 6.3, fat: 0.5, carbs: 16.3, fiber: 7.9 } }, - { name: 'Grãos - Grão de Bico (cozido)', info: { calories: 180, protein: 9.5, fat: 3, carbs: 30, fiber: 8.6 } }, - { name: 'Grãos - Pão integral de forma', info: { calories: 253, protein: 9.4, fat: 3.7, carbs: 49.9, fiber: 6.9 } }, - { name: 'Grãos - Pipoca c/óleo', info: { calories: 448, protein: 9.9, fat: 15.9, carbs: 70.3, fiber: 14.3 } }, - { name: 'Grãos - Pipoca s/óleo', info: { calories: 178, protein: 3.3, fat: 7.2, carbs: 25, fiber: 4.3 } }, - { name: 'Grãos - Quinoa (cozida)', info: { calories: 158, protein: 5.55, fat: 2.5, carbs: 29, fiber: 2.5 } }, - - { name: 'Castanhas - Amêndoas', info: { calories: 581, protein: 18.6, fat: 47.3, carbs: 29.5, fiber: 11.6 } }, - { name: 'Castanhas - Amendoin natural', info: { calories: 611, protein: 26, fat: 49, carbs: 16, fiber: 8.5 } }, - { name: 'Castanhas - Castanha de Caju', info: { calories: 570, protein: 18.5, fat: 46.3, carbs: 29.1, fiber: 3.7 } }, - { name: 'Castanhas - Castanha do Pará', info: { calories: 643, protein: 14.5, fat: 63.5, carbs: 15.1, fiber: 7.9 } }, + // Proteínas - Proteins + { name: 'Atum Sólido, natural', info: { calories: 135, protein: 28.3, fat: 2.7, carbs: 0, fiber: 0, category: 'proteins' } }, + { name: 'Filé de Tilápia, cozido', info: { calories: 128, protein: 26.1, fat: 2.6, carbs: 0, fiber: 0, category: 'proteins' } }, + { name: 'Ovo inteiro, cozido', info: { calories: 146, protein: 13.3, fat: 9.5, carbs: 0.6, fiber: 0, category: 'proteins' } }, + { name: 'Ovo clara, cozido', info: { calories: 59, protein: 13.4, fat: 0.1, carbs: 0, fiber: 0, category: 'proteins' } }, + { name: 'PTS, crua', info: { calories: 288, protein: 52, fat: 0, carbs: 20, fiber: 14, category: 'proteins' } }, + { name: 'Patinho moído, grelhado', info: { calories: 219, protein: 35.9, fat: 7.3, carbs: 0, fiber: 0, category: 'proteins' } }, + { name: 'Soja em Pó Growth', info: { calories: 400, protein: 86.7, fat: 5, carbs: 3.3, fiber: 0, category: 'proteins' } }, + { name: 'Sobrecoxa s/pele, cozida', info: { calories: 245, protein: 24.9, fat: 15.4, carbs: 0, fiber: 0, category: 'proteins' } }, + { name: 'Tofu', info: { calories: 65, protein: 6.5, fat: 4, carbs: 2, fiber: 0.75, category: 'proteins' } }, + { name: 'Feijão preto, cozido', info: { calories: 77, protein: 4.5, fat: 0.5, carbs: 14, fiber: 8.4, category: 'proteins' } }, + { name: 'Lentilha, cozida', info: { calories: 93, protein: 6.3, fat: 0.5, carbs: 16.3, fiber: 7.9, category: 'proteins' } }, + { name: 'Grão de Bico, cozido', info: { calories: 180, protein: 9.5, fat: 3, carbs: 30, fiber: 8.6, category: 'proteins' } }, - { name: 'Sementes - Semente de Chia', info: { calories: 490, protein: 15.6, fat: 30.7, carbs: 43.8, fiber: 37.7 } }, - { name: 'Sementes - Semente de Linhaça', info: { calories: 495, protein: 14.1, fat: 32.3, carbs: 43.3, fiber: 33.5 } }, - { name: 'Sementes - Semente de Gergelim', info: { calories: 584, protein: 21.2, fat: 50.4, carbs: 21.6, fiber: 11.9 } }, - - { name: 'Lanches - 70% Nibs Garoto', info: { calories: 544, protein: 8.4, fat: 40, carbs: 34, fiber: 0 } }, - { name: 'Lanches - Barra de Proteína Vegana Growth', info: { calories: 400, protein: 25, fat: 22, carbs: 25, fiber: 8 } }, - { name: 'Lanches - Goiabada', info: { calories: 320, protein: 0, fat: 0, carbs: 80, fiber: 4.5 } }, - { name: 'Lanches - Goma de Tapioca', info: { calories: 226, protein: 0, fat: 0, carbs: 57, fiber: 0 } }, - { name: 'Lanches - Mel Silvestre', info: { calories: 230, protein: 0, fat: 0, carbs: 65, fiber: 0 } }, - { name: 'Lanches - Melado', info: { calories: 297, protein: 0, fat: 0, carbs: 76.6, fiber: 0 } }, - { name: 'Lanches - Pasta de Amendoim Growth', info: { calories: 544, protein: 27, fat: 33, carbs: 20, fiber: 8 } }, - { name: 'Lanches - Tâmara desidratada', info: { calories: 230, protein: 0.3, fat: 33, carbs: 63.3, fiber: 7 } }, + // Carboidratos, amiláceos - Carbs + { name: 'Banana Nanica', info: { calories: 92, protein: 1.4, fat: 0.1, carbs: 23.8, fiber: 1.9, category: 'carbs (high)' } }, + { name: 'Manga Palmer', info: { calories: 72, protein: 0.4, fat: 0.2, carbs: 19.4, fiber: 1.6, category: 'carbs (high)' } }, + { name: 'Mamão', info: { calories: 40, protein: 0.5, fat: 0.1, carbs: 10.4, fiber: 1, category: 'carbs (high)' } }, + { name: 'Batata doce, assada', info: { calories: 90, protein: 2.0, fat: 0.1, carbs: 20.7, fiber: 3.3, category: 'carbs (high)' } }, + { name: 'Batata doce, cozida', info: { calories: 77, protein: 0.6, fat: 0.1, carbs: 18.4, fiber: 2.2, category: 'carbs (high)' } }, + { name: 'Batata doce, crua', info: { calories: 118, protein: 1.3, fat: 0.1, carbs: 28.2, fiber: 2.6, category: 'carbs (high)' } }, + { name: 'Batata inglesa, assada', info: { calories: 94, protein: 2.1, fat: 0.1, carbs: 21.8, fiber: 2.1, category: 'carbs (high)' } }, + { name: 'Batata inglesa, cozida', info: { calories: 52, protein: 1.2, fat: 0, carbs: 11.9, fiber: 1.3, category: 'carbs (high)' } }, + { name: 'Batata inglesa, crua', info: { calories: 64, protein: 1.8, fat: 0, carbs: 14.7, fiber: 1.2, category: 'carbs (high)' } }, + { name: 'Mandioca, cozida', info: { calories: 125, protein: 0.6, fat: 0.3, carbs: 30.1, fiber: 1.6, category: 'carbs (high)' } }, + { name: 'Pão Francês', info: { calories: 300, protein: 8, fat: 3.1, carbs: 58.6, fiber: 2.3, category: 'carbs (high)' } }, + { name: 'Polenta, cozida', info: { calories: 192, protein: 4.8, fat: 1.2, carbs: 40, fiber: 3.8, category: 'carbs (high)' } }, + { name: 'Arroz integral, cozido', info: { calories: 130, protein: 2.7, fat: 0.3, carbs: 28, fiber: 0.4, category: 'carbs (high)' } }, + { name: 'Aveia', info: { calories: 394, protein: 13.9, fat: 8.5, carbs: 66.6, fiber: 9.1, category: 'carbs (high)' } }, + { name: 'Ervilha, cozida', info: { calories: 88, protein: 7.5, fat: 0.5, carbs: 14.2, fiber: 9.7, category: 'carbs (high)' } }, + { name: 'Pão integral de forma', info: { calories: 253, protein: 9.4, fat: 3.7, carbs: 49.9, fiber: 6.9, category: 'carbs (high)' } }, + { name: 'Pipoca c/óleo', info: { calories: 448, protein: 9.9, fat: 15.9, carbs: 70.3, fiber: 14.3, category: 'carbs (high)' } }, + { name: 'Pipoca s/óleo', info: { calories: 178, protein: 3.3, fat: 7.2, carbs: 25, fiber: 4.3, category: 'carbs (high)' } }, + { name: 'Quinoa, cozida', info: { calories: 158, protein: 5.55, fat: 2.5, carbs: 29, fiber: 2.5, category: 'carbs (high)' } }, + { name: '70% Nibs Garoto', info: { calories: 544, protein: 8.4, fat: 40, carbs: 34, fiber: 0, category: 'carbs (high)' } }, + { name: 'Barra de Proteína Vegana Growth', info: { calories: 400, protein: 25, fat: 22, carbs: 25, fiber: 8, category: 'carbs (high)' } }, + { name: 'Goiabada', info: { calories: 320, protein: 0, fat: 0, carbs: 80, fiber: 4.5, category: 'carbs (high)' } }, + { name: 'Goma de Tapioca', info: { calories: 226, protein: 0, fat: 0, carbs: 57, fiber: 0, category: 'carbs (high)' } }, + { name: 'Mel Silvestre', info: { calories: 230, protein: 0, fat: 0, carbs: 65, fiber: 0, category: 'carbs (high)' } }, + { name: 'Melado', info: { calories: 297, protein: 0, fat: 0, carbs: 76.6, fiber: 0, category: 'carbs (high)' } }, + { name: 'Tâmara desidratada', info: { calories: 230, protein: 0.3, fat: 33, carbs: 63.3, fiber: 7, category: 'carbs (high)' } }, - { name: 'Óleos - Azeite de Oliva EV', info: { calories: 844, protein: 0, fat: 100, carbs: 0, fiber: 0 } } + // Folhas e verduras - Leaves + { name: 'Agrião', info: { calories: 17, protein: 2.7, fat: 0.2, carbs: 2.3, fiber: 2.1, category: 'leaves' } }, + { name: 'Espinafre', info: { calories: 16, protein: 2, fat: 0.2, carbs: 2.6, fiber: 2.1, category: 'leaves' } }, + { name: 'Rúcula', info: { calories: 13, protein: 1.8, fat: 0.1, carbs: 2.2, fiber: 1.7, category: 'leaves' } }, + { name: 'Spirulina', info: { calories: 290, protein: 57.5, fat: 23.9, carbs: 7.7, fiber: 0, category: 'leaves' } }, + + // Frutas - Fruits + { name: 'Abacaxi', info: { calories: 48, protein: 0.9, fat: 0.1, carbs: 12.3, fiber: 1, category: 'fruits' } }, + { name: 'Laranja', info: { calories: 37, protein: 1, fat: 0.1, carbs: 8.9, fiber: 0.8, category: 'fruits' } }, + { name: 'Maçã', info: { calories: 56, protein: 0.3, fat: 0, carbs: 15.2, fiber: 1.3, category: 'fruits' } }, + { name: 'Melancia', info: { calories: 33, protein: 0.9, fat: 0, carbs: 8.1, fiber: 0.1, category: 'fruits' } }, + { name: 'Melão', info: { calories: 29, protein: 0.7, fat: 0, carbs: 7.5, fiber: 0.3, category: 'fruits' } }, + { name: 'Uva', info: { calories: 53, protein: 0.7, fat: 0.2, carbs: 13.6, fiber: 0.9, category: 'fruits' } }, + + // Low carb + { name: 'Abóbora Cabotian, crua', info: { calories: 39, protein: 1.7, fat: 0.5, carbs: 8.4, fiber: 2.2, category: 'carbs (low)' } }, + { name: 'Abóbora Cabotian, cozida', info: { calories: 48, protein: 1.4, fat: 0.7, carbs: 10.8, fiber: 2.5, category: 'carbs (low)' } }, + { name: 'Cenoura, cozida', info: { calories: 30, protein: 0.8, fat: 0.2, carbs: 6.7, fiber: 2.6, category: 'carbs (low)' } }, + { name: 'Tomate', info: { calories: 15, protein: 1.1, fat: 0.2, carbs: 3.1, fiber: 1.2, category: 'carbs (low)' } }, + { name: 'Brócolis, cozido', info: { calories: 25, protein: 2.1, fat: 0.5, carbs: 4.4, fiber: 3.4, category: 'carbs (low)' } }, + { name: 'Couve flor, cozida', info: { calories: 19, protein: 1.2, fat: 0.3, carbs: 3.9, fiber: 2.1, category: 'carbs (low)' } }, + { name: 'Pepino', info: { calories: 10, protein: 0.9, fat: 0, carbs: 2, fiber: 1.1, category: 'carbs (low)' } }, + { name: 'Chuchu, cozido', info: { calories: 19, protein: 0.4, fat: 0, carbs: 4.9, fiber: 1.0, category: 'carbs (low)' } }, + + ]; diff --git a/src/index.ts b/src/index.ts index b365b6a..a4b3df9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,10 @@ import swal from 'sweetalert'; // App state let selectedDate = new Date(); let currentViewDate = new Date(); +let searchTimeout: number | null = null; +let selectedFood: FoodItem | null = null; // review here +let currentHighlightIndex: number = -1; +let currentResults: FoodItem[] = []; // Authentication state let currentUser: any | null = null; @@ -19,11 +23,13 @@ const settingsContent = document.getElementById('settings-content'); const loadingOverlay = getDivById('loading-overlay'); const loginForm = document.getElementById('login-form'); const registerForm = document.getElementById('register-form'); +const searchInput = getInputById('foodSearchInput'); +const searchLoading = document.getElementById('searchLoading'); +const searchResults = getDivById('searchResults'); // Initialize when page loads document.addEventListener('DOMContentLoaded', async function() { await initializeAuth(); - populateFoodSelect(); updateCurrentDate(); setupEventListeners(); }); @@ -223,7 +229,7 @@ async function handleSettings() { getInputById('fiberGoal').value = ''; } - getButtonById('settingsBtn').textContent = 'Back to App'; + getButtonById('settingsBtn').textContent = 'Back'; appContent?.classList.add('hidden'); settingsContent?.classList.remove('hidden'); @@ -275,8 +281,9 @@ function hideLoading() { function clearAppData() { getDivById('foodTableBody').innerHTML = ''; getDivById('caloriesCounter').textContent = '0'; - getInputById('foodSelect').value = ''; + getInputById('foodSearchInput').value = ''; getInputById('gramAmount').value = '100'; + selectedFood = null; } const getFoodData = (grams: number, foodData: FoodItem): FoodItem => { @@ -288,7 +295,8 @@ const getFoodData = (grams: number, foodData: FoodItem): FoodItem => { protein: Math.round(foodData.info.protein * multiplier * 10) / 10, fat: Math.round(foodData.info.fat * multiplier * 10) / 10, carbs: Math.round(foodData.info.carbs * multiplier * 10) / 10, - fiber: Math.round(foodData.info.fiber * multiplier * 10) / 10 + fiber: Math.round(foodData.info.fiber * multiplier * 10) / 10, + category: foodData.info.category } }; } @@ -301,11 +309,11 @@ const getFoodItemByName = (foodName: string): FoodItem => { return foodDataSearch[0]; } -const previewCalories = () => { - const foodSelect = getInputById('foodSelect'); +const previewCalories = (foodSelected?: FoodItem) => { + const foodToPreview = foodSelected ?? selectedFood; const gramAmount = getInputById('gramAmount'); - if (!foodSelect.value) { + if (!foodToPreview) { showFoodPreview(false); return; } @@ -315,7 +323,7 @@ const previewCalories = () => { grams = parseFloat(gramAmount.value); } - const foodData: FoodItem = getFoodItemByName(foodSelect.value); + const foodData: FoodItem = getFoodItemByName(foodToPreview.name); const proportion = getFoodData(grams, foodData); getDivById('calorieValuePreview').textContent = proportion.info.calories.toString(); @@ -328,8 +336,11 @@ const previewCalories = () => { } const setupEventListeners = () => { - getInputById('foodSelect').addEventListener('change', () => { - previewCalories(); + getInputById('foodSearchInput').addEventListener('change', (e: Event) => { + const target = e.target as HTMLInputElement; + if (target.value === ''){ + showFoodPreview(false); + } }); getInputById('gramAmount').addEventListener('change', () => { @@ -365,6 +376,146 @@ const setupEventListeners = () => { document.getElementById('logoutBtn')?.addEventListener('click', handleLogout); document.getElementById('settingsBtn')?.addEventListener('click', handleSettings); document.getElementById('settingsForm')?.addEventListener('submit', handleSaveSettings); + + // Search functionality + searchInput.addEventListener('input', function(e: Event) { + const target = e.target as HTMLInputElement; + const query = target.value.trim(); + + if (query.length === 0) { + hideSearchResults(); + return; + } + + // Show loading + searchLoading?.classList.add('show'); + + // Clear previous timeout + if (searchTimeout) { + clearTimeout(searchTimeout); + } + + // Debounce search + searchTimeout = setTimeout(() => { + performSearch(query); + }, 300); + }); + + // Keyboard navigation + searchInput?.addEventListener('keydown', function(e) { + if (!searchResults?.classList.contains('show')) return; + + switch(e.key) { + case 'ArrowDown': + e.preventDefault(); + navigateResults(1); + break; + case 'ArrowUp': + e.preventDefault(); + navigateResults(-1); + break; + case 'Enter': + e.preventDefault(); + if (currentHighlightIndex >= 0 && currentResults[currentHighlightIndex]) { + selectFood(currentResults[currentHighlightIndex]); + } + break; + case 'Escape': + hideSearchResults(); + break; + } + }); + + // Click outside to close + document.addEventListener('click', function(e: Event) { + const target = e.target as HTMLElement; + if (!searchResults.contains(target) && !searchInput.contains(target)) { + hideSearchResults(); + } + }); +} + +// Perform search +function performSearch(query: string) { + // Simulate API call - replace with your actual database search + const results: FoodItem[] = foodDatabase.filter(food => + food.name.toLowerCase().includes(query.toLowerCase()) || + food.info.category.toLowerCase().includes(query.toLowerCase()) + ).slice(0, 5); // Limit to 5 results + + currentResults = results; + displaySearchResults(results); + searchLoading?.classList.remove('show'); +} + +// Display search results +function displaySearchResults(results: FoodItem[]) { + if (results.length === 0) { + searchResults.innerHTML = '
No foods found. Try a different search term.
'; + } else { + const icons = { + 'fats': '🥑', + 'proteins': '🫘', + 'carbs (high)': '🍞', + 'leaves': '🥬', + 'fruits': '🍊', + 'carbs (low)': '🍍' + }; + + searchResults.innerHTML = results.map((food, index) => ` +
+
+
${icons[food.info.category]} ${food.name}
+
${food.info.category} • 100 g
+
+
${food.info.calories} cal
+
+ `).join(''); + } + + searchResults.classList.add('show'); + currentHighlightIndex = -1; +} + +// Navigate results with keyboard +function navigateResults(direction: number) { + const items = searchResults.querySelectorAll('.search-result-item'); + if (items.length === 0) return; + + // Remove current highlight + if (currentHighlightIndex >= 0) { + items[currentHighlightIndex].classList.remove('highlighted'); + } + + // Calculate new index + currentHighlightIndex += direction; + if (currentHighlightIndex < 0) currentHighlightIndex = items.length - 1; + if (currentHighlightIndex >= items.length) currentHighlightIndex = 0; + + // Add new highlight + items[currentHighlightIndex].classList.add('highlighted'); + items[currentHighlightIndex].scrollIntoView({ block: 'nearest' }); +} + +// Select food +function selectFood(food: FoodItem) { + selectedFood = food; + + // Clear search and hide results + searchInput.value = food.name; + hideSearchResults(); + + // Focus on quantity input + getInputById('gramAmount').focus(); + + // Update calories + previewCalories(food); +} + +// Hide search results +function hideSearchResults() { + searchResults.classList.remove('show'); + currentHighlightIndex = -1; } const addDeleteEvents = () => { @@ -381,20 +532,6 @@ const addDeleteEvents = () => { }); } -// Populate food select dropdown -const populateFoodSelect = () => { - const select = getInputById('foodSelect'); - select.innerHTML = ''; - - const sortedFoods = foodDatabase.sort((f1, f2) => f1.name.localeCompare(f2.name)); - sortedFoods.forEach((food: FoodItem) => { - const option = document.createElement('option') as HTMLOptionElement; - option.value = food.name; - option.textContent = food.name; - select.appendChild(option); - }); -} - // Update current date display const updateCurrentDate = () => { const date = new Date(selectedDate); @@ -413,10 +550,9 @@ const addFood = async () => { return; } - const foodSelect = getInputById('foodSelect'); const gramAmount = getInputById('gramAmount'); - if (!foodSelect.value || !gramAmount.value) { + if (!selectedFood || !gramAmount.value) { swal('Hey!', 'Please select a food item and enter amount', 'error'); return; } @@ -425,19 +561,22 @@ const addFood = async () => { try { const grams: number = parseFloat(gramAmount.value); - const foodData: FoodItem = getFoodItemByName(foodSelect.value); + const foodData: FoodItem = getFoodItemByName(selectedFood.name); + + // Current date, with timezone + const date = new Date(selectedDate.getTime() - (selectedDate.getTimezoneOffset() * 60000)).toISOString(); // Calculate nutrition for the amount const proportion: FoodItem = getFoodData(grams, foodData); const entry: FoodStorage = { - name: foodSelect.value, + name: selectedFood.name, grams: grams, calories: proportion.info.calories, protein: proportion.info.protein, fat: proportion.info.fat, carbs: proportion.info.carbs, fiber: proportion.info.fiber, - date: selectedDate.toISOString().split('T')[0], + date: date.split('T')[0], time: new Date().toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', @@ -471,7 +610,8 @@ const addFood = async () => { fiberDiv.textContent = (Math.round(totalFiber * 10) / 10).toString(); // Reset form - foodSelect.value = ''; + selectedFood = null; + getInputById('foodSearchInput').value = ''; gramAmount.value = '100'; showFoodPreview(false); } catch (error) { @@ -772,4 +912,4 @@ function createDayElement(day: number, isOtherMonth: boolean, year: number, mont return dayElement; } - +(window as any).selectFood = selectFood; diff --git a/src/types.ts b/src/types.ts index 780b63c..c888e2a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,8 @@ +type FoodCategory = 'fats' | 'proteins' | 'carbs (high)' | 'leaves' | 'fruits' | 'carbs (low)'; + export type FoodItem = { name: string; - info: { calories: number, protein: number, fat: number, carbs: number, fiber: number } + info: { calories: number, protein: number, fat: number, carbs: number, fiber: number, category: FoodCategory } } export type FoodStorage = { diff --git a/style.css b/style.css index c1f3d8f..06f7864 100644 --- a/style.css +++ b/style.css @@ -5,18 +5,19 @@ } body { - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + background: #f5f5f5; min-height: 100vh; - padding: 20px; + padding: 12px; color: #333; + line-height: 1.6; } .container { max-width: 1200px; margin: 0 auto; background: rgba(255, 255, 255, 0.95); - border-radius: 20px; + border-radius: 6px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2); padding: 40px; backdrop-filter: blur(10px); @@ -34,8 +35,8 @@ h1 { text-align: center; background: linear-gradient(135deg, #FF6B6B, #4ECDC4); color: white; - padding: 60px 40px; - border-radius: 15px; + padding: 30px 20px; + border-radius: 6px; margin-bottom: 30px; box-shadow: 0 10px 30px rgba(255, 107, 107, 0.3); transition: transform 0.3s ease; @@ -59,16 +60,131 @@ h1 { .date-display { text-align: center; - font-size: 1.5rem; + font-size: 1.1rem; margin-bottom: 30px; color: #4a5568; font-weight: 500; } +.food-search-container { + position: relative; + z-index: 1001; /* Higher than other elements */ +} + +.food-search-input { + width: 100%; + padding: 15px 20px; + border: 2px solid #e0e0e0; + border-radius: 6px; + font-size: 16px; + transition: all 0.3s ease; + background: white; + outline: none; +} + +.food-search-input:focus { + border-color: #667eea; + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); +} + +.food-search-input::placeholder { + color: #999; +} + +/* Loading indicator */ +.search-loading { + position: absolute; + right: 15px; + top: 30%; + transform: translateY(-50%); + width: 20px; + height: 20px; + border: 2px solid #e0e0e0; + border-top: 2px solid #667eea; + border-radius: 50%; + animation: spin 1s linear infinite; + display: none; +} + +.search-loading.show { + display: block; +} + +@keyframes spin { + 0% { transform: translateY(-50%) rotate(0deg); } + 100% { transform: translateY(-50%) rotate(360deg); } +} + +/* Search Results Overlay */ +.search-results { + position: absolute; + top: 100%; + left: 0; + right: 0; + background: white; + border: 1px solid #e0e0e0; + border-radius: 12px; + box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); + z-index: 1002; + max-height: 300px; + overflow-y: auto; + display: none; + margin-top: 5px; +} + +.search-results.show { + display: block; +} + +.search-result-item { + padding: 15px 20px; + border-bottom: 1px solid #f0f0f0; + cursor: pointer; + transition: background-color 0.2s ease; + display: flex; + justify-content: space-between; + align-items: center; + background: white; +} + +.search-result-item:last-child { + border-bottom: none; +} + +.search-result-item:hover, +.search-result-item.highlighted { + background-color: #f8f9ff; +} + + +.food-name { + font-weight: 600; + color: #333; + margin-bottom: 2px; +} + +.food-details { + font-size: 13px; + color: #666; +} + +.food-calories { + font-weight: 600; + color: #667eea; + font-size: 14px; +} + +.no-results { + padding: 20px; + text-align: center; + color: #666; + font-style: italic; +} + .add-food-section { background: white; padding: 30px; - border-radius: 15px; + border-radius: 6px; margin-bottom: 30px; box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1); } @@ -85,7 +201,6 @@ h1 { grid-template-columns: 2fr 1fr auto; gap: 15px; align-items: end; - overflow: hidden; } .display-none { @@ -108,28 +223,34 @@ label { color: #4a5568; } -select, input { - padding: 12px; - border: 2px solid #e2e8f0; - border-radius: 8px; - font-size: 1rem; - transition: border-color 0.3s ease; +#gramAmount { width: 100%; + padding: 15px 20px; + border: 2px solid #e0e0e0; + border-radius: 6px; + font-size: 1rem; + transition: all 0.3s ease; + background: white; min-width: 0; box-sizing: border-box; + outline: none; } -select:focus, input:focus { - outline: none; +#gramAmount:focus { border-color: #667eea; + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); +} + +#gramAmount::placeholder { + color: #999; } .add-btn { - padding: 12px 25px; + padding: 17px 25px; background: linear-gradient(135deg, #4CAF50, #45a049); color: white; border: none; - border-radius: 8px; + border-radius: 6px; cursor: pointer; font-size: 1rem; font-weight: 600; @@ -144,7 +265,7 @@ select:focus, input:focus { .food-table-section { background: white; - border-radius: 15px; + border-radius: 6px; margin-bottom: 30px; box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1); overflow: hidden; @@ -194,7 +315,7 @@ select:focus, input:focus { color: white; border: none; padding: 5px 10px; - border-radius: 5px; + border-radius: 6px; cursor: pointer; font-size: 0.8rem; transition: background 0.3s ease; @@ -206,7 +327,7 @@ select:focus, input:focus { .calendar-section { background: white; - border-radius: 15px; + border-radius: 6px; box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1); overflow: hidden; } @@ -225,7 +346,7 @@ select:focus, input:focus { border: none; color: white; padding: 10px 15px; - border-radius: 8px; + border-radius: 6px; cursor: pointer; font-size: 1.1rem; transition: background 0.3s ease; @@ -314,14 +435,14 @@ select:focus, input:focus { margin-top: 20px; padding: 20px; background: #f8fafc; - border-radius: 10px; + border-radius: 6px; } .nutrition-item { text-align: center; padding: 10px; background: white; - border-radius: 8px; + border-radius: 6px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); } @@ -390,4 +511,4 @@ select:focus, input:focus { h1 { font-size: 2rem; } -} \ No newline at end of file +}