index.html 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>LocalFoodAI Chat</title>
  7. <meta name="description" content="LocalFoodAI Assistant for Nutritional Information and Menu Proposals">
  8. <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
  9. <link rel="stylesheet" href="/static/style.css">
  10. </head>
  11. <body>
  12. <div class="app-container" id="chat-app" style="display: none;">
  13. <header class="chat-header">
  14. <div class="brand">
  15. <div class="logo">🍳</div>
  16. <div>
  17. <h1>LocalFoodAI</h1>
  18. <span class="status-indicator" id="status-dot"></span><span class="status-text" id="status-text">Local LLM Ready</span>
  19. </div>
  20. </div>
  21. <div class="actions">
  22. <span id="user-greeting" style="margin-right:15px; font-size: 0.9rem; color: var(--text-muted);"></span>
  23. <button id="nav-dashboard-btn" class="nav-btn">Dashboard</button>
  24. <button id="nav-logout-btn" class="nav-btn">Logout</button>
  25. <button id="clear-chat" title="Clear Chat">
  26. <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"></path></svg>
  27. </button>
  28. </div>
  29. </header>
  30. <!-- New Visual Food Search Component -->
  31. <div class="search-module" id="food-search-module">
  32. <div class="search-input-wrapper">
  33. <svg class="search-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
  34. <input type="text" id="food-search-input" placeholder="Search for standard foods or raw ingredients..." autocomplete="off">
  35. <button id="clear-search-btn" style="display: none;" title="Clear search">
  36. <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
  37. </button>
  38. </div>
  39. <div class="search-results-dropdown" id="search-results-dropdown" style="display: none;">
  40. <!-- Dynamically populated by JS fetch -->
  41. </div>
  42. </div>
  43. <!-- Meal Builder Component (US-10 Task #46) -->
  44. <div class="meal-builder-tray" id="meal-builder">
  45. <div class="meal-builder-header">
  46. <div class="tray-title">
  47. <span class="icon">🍽️</span>
  48. <h3>Meal Builder</h3>
  49. <span class="item-count" id="meal-item-count">0 items</span>
  50. </div>
  51. <button id="toggle-meal-btn" class="icon-btn" title="Toggle Meal Builder">
  52. <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 9l-7 7-7-7"></path></svg>
  53. </button>
  54. </div>
  55. <div class="meal-content collapsed" id="meal-content">
  56. <div class="meal-items-list" id="meal-items-list">
  57. <!-- Dynamic food rows added here -->
  58. <div class="empty-meal-msg" id="empty-meal-msg">No foods added yet. Use the search + button to build a meal.</div>
  59. </div>
  60. <div class="meal-builder-footer" id="meal-builder-footer" style="display: none;">
  61. <div class="meal-totals-banner" id="meal-totals-banner">
  62. <div class="totals-header">
  63. <span class="totals-title">Total Macros</span>
  64. <span class="totals-weight" id="meal-total-weight">0g</span>
  65. </div>
  66. <div class="totals-grid">
  67. <div class="total-card">
  68. <span class="total-val" id="meal-total-cal">0</span>
  69. <span class="total-lbl">kcal</span>
  70. </div>
  71. <div class="total-card protein-highlight">
  72. <span class="total-val" id="meal-total-pro">0</span>
  73. <span class="total-lbl">Protein</span>
  74. </div>
  75. <div class="total-card">
  76. <span class="total-val" id="meal-total-fat">0</span>
  77. <span class="total-lbl">Fat</span>
  78. </div>
  79. <div class="total-card">
  80. <span class="total-val" id="meal-total-carb">0</span>
  81. <span class="total-lbl">Carbs</span>
  82. </div>
  83. </div>
  84. </div>
  85. <div class="meal-builder-actions" style="display: flex; gap: 10px; margin-top: 15px;">
  86. <button id="generate-recipe-btn" class="primary-btn-sm" style="flex: 1;">🍲 Generate Recipe Prompt</button>
  87. <button id="open-save-modal-btn" class="secondary-btn-sm" title="Save this meal list">💾 Save Meal</button>
  88. </div>
  89. </div>
  90. </div>
  91. </div>
  92. <!-- Macro Dashboard UI (US-07 Task #38) -->
  93. <div class="macro-dashboard" id="macro-dashboard" style="display: none;">
  94. <div class="macro-card">
  95. <div class="macro-label">Calories</div>
  96. <div class="macro-value" id="macro-calories">-- kcal</div>
  97. </div>
  98. <div class="macro-card">
  99. <div class="macro-label">Protein</div>
  100. <div class="macro-value" id="macro-protein">-- g</div>
  101. </div>
  102. <div class="macro-card">
  103. <div class="macro-label">Carbs</div>
  104. <div class="macro-value" id="macro-carbs">-- g</div>
  105. </div>
  106. <div class="macro-card">
  107. <div class="macro-label">Fat</div>
  108. <div class="macro-value" id="macro-fat">-- g</div>
  109. </div>
  110. </div>
  111. <main class="chat-container" id="chat-container">
  112. <div class="message system">
  113. <div class="avatar">🤖</div>
  114. <div class="message-content">
  115. <p>Hello! I am LocalFoodAI, your completely local nutrition and menu assistant. How can I help you today?</p>
  116. </div>
  117. </div>
  118. </main>
  119. <footer class="chat-input-area">
  120. <form id="chat-form" class="input-form">
  121. <textarea id="user-input" placeholder="Ask about recipes, nutrition, menus..." rows="1" required></textarea>
  122. <button type="submit" id="send-btn" class="send-btn" aria-label="Send message">
  123. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"></line><polygon points="22 2 15 22 11 13 2 9 22 2"></polygon></svg>
  124. </button>
  125. </form>
  126. <div class="footer-note">Powered by Qwen 3.5:4B running locally on Ubuntu 24.04 via Ollama</div>
  127. </footer>
  128. <!-- Save Meal Modal (Sprint 8) -->
  129. <div class="modal" id="save-meal-modal" style="display: none;">
  130. <div class="modal-content">
  131. <div class="modal-header">
  132. <h3>💾 Save Meal Combination</h3>
  133. <button id="close-save-modal-btn" class="close-btn">&times;</button>
  134. </div>
  135. <div class="modal-body">
  136. <p>Give your meal a name to save it to your personal dashboard.</p>
  137. <div class="input-group" style="margin-top: 15px;">
  138. <label for="meal-name-input">Meal Name</label>
  139. <input type="text" id="meal-name-input" placeholder="e.g. Healthy Salmon Dinner" maxlength="50">
  140. </div>
  141. <div id="save-meal-error" class="error-text"></div>
  142. </div>
  143. <div class="modal-footer">
  144. <button id="cancel-save-btn" class="secondary-btn">Cancel</button>
  145. <button id="confirm-save-btn" class="primary-btn">Save to Dashboard</button>
  146. </div>
  147. </div>
  148. </div>
  149. <!-- Saved Meals Dashboard Overlay (Sprint 8) -->
  150. <div class="dashboard-overlay" id="dashboard-overlay" style="display: none;">
  151. <div class="dashboard-content">
  152. <div class="dashboard-header">
  153. <div class="dashboard-title-group">
  154. <span class="icon">📁</span>
  155. <h2>My Saved Meals</h2>
  156. </div>
  157. <button id="close-dashboard-btn" class="close-btn">&times;</button>
  158. </div>
  159. <div class="dashboard-body">
  160. <div class="dashboard-grid" id="dashboard-grid">
  161. <!-- Meal cards injected here -->
  162. <div class="search-loading">Loading your meals...</div>
  163. </div>
  164. <div id="dashboard-empty-msg" style="display: none;" class="empty-meal-msg">
  165. You haven't saved any meals yet. Build one in the chat and click "Save Meal"!
  166. </div>
  167. </div>
  168. </div>
  169. </div>
  170. </div>
  171. <!-- Authentication Gateway -->
  172. <div class="auth-container" id="auth-screen">
  173. <div class="auth-header">
  174. <div class="logo" style="margin-bottom: 10px;">🍳</div>
  175. <h2>Welcome to LocalFoodAI</h2>
  176. <p>Please log in or create an account to continue.</p>
  177. </div>
  178. <!-- Login Form -->
  179. <form id="login-form">
  180. <div class="input-group">
  181. <label for="login-username">Username</label>
  182. <input type="text" id="login-username" required>
  183. </div>
  184. <div class="input-group">
  185. <label for="login-password">Password</label>
  186. <input type="password" id="login-password" required>
  187. </div>
  188. <div id="login-error" class="error-text"></div>
  189. <button type="submit" class="primary-btn" id="login-submit-btn">Login</button>
  190. <p class="auth-toggle">Don't have an account? <a href="#" id="show-register">Register here</a></p>
  191. </form>
  192. <!-- Registration Form (Hidden by default) -->
  193. <form id="register-form" style="display: none;">
  194. <div class="input-group">
  195. <label for="reg-username">Username</label>
  196. <input type="text" id="reg-username" required minlength="3">
  197. </div>
  198. <div class="input-group">
  199. <label for="reg-password">Password</label>
  200. <input type="password" id="reg-password" required minlength="6">
  201. </div>
  202. <div class="input-group">
  203. <label for="reg-confirm">Confirm Password</label>
  204. <input type="password" id="reg-confirm" required minlength="6">
  205. </div>
  206. <div id="reg-error" class="error-text"></div>
  207. <div id="reg-success" class="success-text"></div>
  208. <button type="submit" class="primary-btn" id="reg-submit-btn">Register</button>
  209. <p class="auth-toggle">Already have an account? <a href="#" id="show-login">Login here</a></p>
  210. </form>
  211. </div>
  212. <script src="/static/script.js"></script>
  213. </body>
  214. </html>