| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Local Food AI - Clinician User Manual Presentation</title>
- <!-- Google Fonts -->
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Outfit:wght@400;500;600;700&family=Fira+Code:wght@400;500&display=swap" rel="stylesheet">
- <style>
- :root {
- --bg-color: #080c10;
- --slide-bg: rgba(13, 17, 23, 0.75);
- --border-color: rgba(255, 255, 255, 0.08);
- --primary-accent: #34d399; /* Emerald accent for users (feels medical/fresh) */
- --secondary-accent: #60a5fa; /* Blue accent */
- --text-primary: #f0f6fc;
- --text-secondary: #8b949e;
- --text-muted: #484f58;
- --code-bg: #161b22;
- --font-display: 'Outfit', sans-serif;
- --font-sans: 'Inter', sans-serif;
- --font-mono: 'Fira Code', monospace;
- --glow-color: rgba(52, 211, 153, 0.15);
- }
- * {
- box-sizing: border-box;
- margin: 0;
- padding: 0;
- }
- body {
- background-color: var(--bg-color);
- background-image:
- radial-gradient(at 0% 0%, rgba(52, 211, 153, 0.08) 0, transparent 50%),
- radial-gradient(at 100% 100%, rgba(96, 165, 250, 0.08) 0, transparent 50%);
- color: var(--text-primary);
- font-family: var(--font-sans);
- overflow: hidden;
- height: 100vh;
- width: 100vw;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- }
- /* Slide Container */
- .presentation-container {
- position: relative;
- width: 90%;
- max-width: 1100px;
- height: 80vh;
- min-height: 550px;
- perspective: 1500px;
- }
- .slide-deck {
- position: relative;
- width: 100%;
- height: 100%;
- transform-style: preserve-3d;
- }
- /* Individual Slides */
- .slide {
- position: absolute;
- width: 100%;
- height: 100%;
- background: var(--slide-bg);
- border: 1px solid var(--border-color);
- border-radius: 16px;
- padding: 3.5rem;
- backdrop-filter: blur(12px);
- -webkit-backdrop-filter: blur(12px);
- box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4), inset 0 1px 1px rgba(255, 255, 255, 0.1);
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- opacity: 0;
- visibility: hidden;
- transform: scale(0.9) translateZ(-100px);
- transition: all 0.6s cubic-bezier(0.25, 0.8, 0.25, 1);
- pointer-events: none;
- }
- /* Slide States for Animations */
- .slide.active {
- opacity: 1;
- visibility: visible;
- transform: scale(1) translateZ(0);
- pointer-events: auto;
- z-index: 10;
- }
- .slide.prev {
- opacity: 0;
- visibility: hidden;
- transform: scale(0.9) translateX(-100%) rotateY(15deg);
- z-index: 5;
- }
- .slide.next {
- opacity: 0;
- visibility: hidden;
- transform: scale(0.9) translateX(100%) rotateY(-15deg);
- z-index: 5;
- }
- /* Content Formatting */
- .slide-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- border-bottom: 1px dashed var(--border-color);
- padding-bottom: 1rem;
- margin-bottom: 1.5rem;
- }
- .slide-header .tag {
- font-family: var(--font-mono);
- font-size: 0.8rem;
- color: var(--secondary-accent);
- text-transform: uppercase;
- letter-spacing: 2px;
- }
- .slide-header .title-badge {
- font-size: 0.75rem;
- padding: 0.25rem 0.75rem;
- border-radius: 20px;
- background: rgba(52, 211, 153, 0.1);
- border: 1px solid rgba(52, 211, 153, 0.2);
- color: var(--primary-accent);
- font-family: var(--font-mono);
- }
- .slide-body {
- flex-grow: 1;
- display: flex;
- flex-direction: column;
- justify-content: center;
- }
- .slide-title {
- font-family: var(--font-display);
- font-size: 2.2rem;
- font-weight: 700;
- line-height: 1.2;
- margin-bottom: 1.5rem;
- background: linear-gradient(135deg, var(--primary-accent), var(--secondary-accent));
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- }
- .slide-footer {
- display: flex;
- justify-content: space-between;
- align-items: center;
- border-top: 1px solid var(--border-color);
- padding-top: 1.2rem;
- margin-top: 1.5rem;
- font-size: 0.8rem;
- color: var(--text-secondary);
- }
- /* Grid Layouts inside slides */
- .slide-grid-2 {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 2rem;
- align-items: start;
- }
- .slide-grid-3 {
- display: grid;
- grid-template-columns: 1fr 1fr 1fr;
- gap: 1.5rem;
- }
- /* Lists and Cards */
- ul {
- list-style: none;
- }
- li {
- position: relative;
- padding-left: 1.5rem;
- margin-bottom: 0.8rem;
- font-size: 1.05rem;
- line-height: 1.5;
- color: var(--text-primary);
- }
- li::before {
- content: "✓";
- position: absolute;
- left: 0;
- color: var(--primary-accent);
- font-weight: bold;
- }
- li.warning-li::before {
- content: "⚠";
- color: #ff7b72;
- }
- li strong {
- color: #fff;
- font-weight: 600;
- }
- .card {
- background: rgba(255, 255, 255, 0.02);
- border: 1px solid rgba(255, 255, 255, 0.05);
- border-radius: 8px;
- padding: 1.2rem;
- transition: all 0.3s ease;
- }
- .card:hover {
- background: rgba(255, 255, 255, 0.04);
- border-color: rgba(52, 211, 153, 0.2);
- box-shadow: 0 4px 20px var(--glow-color);
- transform: translateY(-2px);
- }
- .card-title {
- font-family: var(--font-display);
- font-size: 1.15rem;
- font-weight: 600;
- color: #fff;
- margin-bottom: 0.6rem;
- display: flex;
- align-items: center;
- gap: 0.5rem;
- }
- .card-title .icon {
- color: var(--primary-accent);
- }
- .card-desc {
- font-size: 0.95rem;
- color: var(--text-secondary);
- line-height: 1.4;
- }
- /* Title Slide Layout */
- .title-slide {
- justify-content: center;
- align-items: center;
- text-align: center;
- }
- .title-slide .slide-title {
- font-size: 3.2rem;
- margin-bottom: 1.5rem;
- }
- .title-slide .subtitle {
- font-size: 1.3rem;
- color: var(--text-secondary);
- margin-bottom: 2rem;
- max-width: 700px;
- }
- .meta-grid {
- display: grid;
- grid-template-columns: repeat(3, 160px);
- gap: 1.5rem;
- margin-top: 2rem;
- border-top: 1px solid var(--border-color);
- padding-top: 2rem;
- }
- .meta-item {
- display: flex;
- flex-direction: column;
- align-items: center;
- }
- .meta-label {
- font-size: 0.75rem;
- text-transform: uppercase;
- letter-spacing: 1px;
- color: var(--text-secondary);
- margin-bottom: 0.4rem;
- }
- .meta-value {
- font-size: 0.95rem;
- font-weight: 500;
- color: #fff;
- }
- .highlight-text {
- color: var(--primary-accent);
- font-weight: 500;
- }
- /* Navigation Controls */
- .controls {
- position: absolute;
- bottom: 2.5vh;
- display: flex;
- align-items: center;
- gap: 2rem;
- z-index: 100;
- }
- .nav-btn {
- background: rgba(255, 255, 255, 0.05);
- border: 1px solid var(--border-color);
- border-radius: 50%;
- width: 50px;
- height: 50px;
- color: var(--text-primary);
- cursor: pointer;
- display: flex;
- justify-content: center;
- align-items: center;
- font-size: 1.2rem;
- transition: all 0.2s ease;
- }
- .nav-btn:hover:not(:disabled) {
- background: rgba(52, 211, 153, 0.2);
- border-color: var(--primary-accent);
- box-shadow: 0 0 15px var(--glow-color);
- color: #fff;
- transform: scale(1.05);
- }
- .nav-btn:disabled {
- opacity: 0.3;
- cursor: not-allowed;
- }
- .progress-bar-container {
- width: 250px;
- height: 6px;
- background: rgba(255, 255, 255, 0.05);
- border-radius: 3px;
- overflow: hidden;
- }
- .progress-bar {
- height: 100%;
- width: 0%;
- background: linear-gradient(90deg, var(--primary-accent), var(--secondary-accent));
- border-radius: 3px;
- transition: width 0.4s ease;
- }
- .slide-counter {
- font-family: var(--font-mono);
- font-size: 0.85rem;
- color: var(--text-secondary);
- min-width: 100px;
- text-align: center;
- }
-
- /* Badges */
- .badge {
- display: inline-block;
- padding: 0.2rem 0.6rem;
- font-size: 0.8rem;
- font-weight: 600;
- border-radius: 4px;
- text-transform: uppercase;
- }
- .badge-red { background: rgba(239, 68, 68, 0.15); border: 1px solid rgba(239, 68, 68, 0.3); color: #f87171; }
- .badge-green { background: rgba(16, 185, 129, 0.15); border: 1px solid rgba(16, 185, 129, 0.3); color: #34d399; }
-
- </style>
- </head>
- <body>
- <div class="presentation-container">
- <div class="slide-deck">
- <!-- Slide 1: Title -->
- <div class="slide title-slide active">
- <div class="slide-header">
- <span class="tag">Local Food AI</span>
- <span class="title-badge">USER GUIDE</span>
- </div>
- <div class="slide-body">
- <h1 class="slide-title">Local Food AI Platform</h1>
- <p class="subtitle">Clinician User Manual & Functional Application Walkthrough</p>
- <div class="meta-grid">
- <div class="meta-item">
- <span class="meta-label">Audience</span>
- <span class="meta-value">Clinical Staff & Users</span>
- </div>
- <div class="meta-item">
- <span class="meta-label">Author</span>
- <span class="meta-value">Francois Lange</span>
- </div>
- <div class="meta-item">
- <span class="meta-label">Status</span>
- <span class="meta-value">Ready (production)</span>
- </div>
- </div>
- </div>
- <div class="slide-footer">
- <span>Domain-specific Project 1 (DSP1) - Clinical Guide</span>
- <span>1 / 9</span>
- </div>
- </div>
- <!-- Slide 2: Vision -->
- <div class="slide">
- <div class="slide-header">
- <span class="tag">Project Vision</span>
- <span class="title-badge">PRIVACY FIRST</span>
- </div>
- <div class="slide-body">
- <h2 class="slide-title">The Vision: A Privacy-First Clinical Dietitian</h2>
- <div class="slide-grid-2">
- <div>
- <ul>
- <li><strong>Complete HIPAA Compliance</strong>: Patient dietary parameters, medical diagnoses, and recipe histories remain 100% inside your building.</li>
- <li><strong>Adaptive AI Specialist</strong>: The local AI engine adapts instantly to user selections (e.g., pregnancy, kidney disease, diabetes).</li>
- <li><strong>Fully Local RAG Intelligence</strong>: Bypasses slow and risky cloud queries by retrieving context entirely from in-house databases.</li>
- </ul>
- </div>
- <div class="card" style="border-color: rgba(52, 211, 153, 0.2);">
- <div class="card-title"><span class="icon">🔒</span> Air-Gapped Advantage</div>
- <div class="card-desc">
- "Unlike ChatGPT or consumer dietary trackers, Local Food AI never leaks clinic logs or clinician search strings to third-party databases."
- </div>
- </div>
- </div>
- </div>
- <div class="slide-footer">
- <span>Local Food AI - User Presentation</span>
- <span>2 / 9</span>
- </div>
- </div>
- <!-- Slide 3: Secure Logging -->
- <div class="slide">
- <div class="slide-header">
- <span class="tag">Access Control</span>
- <span class="title-badge">LOGIN & SECURITY</span>
- </div>
- <div class="slide-body">
- <h2 class="slide-title">Secure Authentication & Password Recovery</h2>
- <div class="slide-grid-2">
- <div>
- <ul>
- <li><strong>Bcrypt Hashed Credentials</strong>: Heavy database level encryption blocks unauthorized entry.</li>
- <li><strong>Sidebar Session Status</strong>: Displays the active user, network mode, and active LLM version details.</li>
- <li><strong>Outbound Email Recovery</strong>: Integrated password reset routing via secure internal SMTP relays.</li>
- </ul>
- </div>
- <div class="slide-grid-2" style="grid-template-columns: 1fr; gap: 1rem;">
- <div class="card">
- <div class="card-title"><span class="icon">👤</span> Cookie Timeout</div>
- <div class="card-desc">Secures sessions on shared ward computers, preventing patient detail access.</div>
- </div>
- <div class="card">
- <div class="card-title"><span class="icon">🔑</span> Self-Serve Resets</div>
- <div class="card-desc">Request reset loops dispatch direct recovery keys to the clinician's inbox.</div>
- </div>
- </div>
- </div>
- </div>
- <div class="slide-footer">
- <span>Local Food AI - User Presentation</span>
- <span>3 / 9</span>
- </div>
- </div>
- <!-- Slide 4: Data Search -->
- <div class="slide">
- <div class="slide-header">
- <span class="tag">Clinical Search</span>
- <span class="title-badge">DATABASE FILTERS</span>
- </div>
- <div class="slide-body">
- <h2 class="slide-title">Tab 1: High-Speed Database Exploration</h2>
- <div class="slide-grid-2">
- <div>
- <ul>
- <li><strong>Real-Time Searching</strong>: Access millions of OpenFoodFacts entries in under <span class="highlight-text">0.04 seconds</span>.</li>
- <li><strong>Dynamic Warnings</strong>: Automatically overlays warning indicators based on active patient profile constraints.</li>
- <li><strong>Flexible Column Config</strong>: Custom selections allow dietitians to inspect precise vitamins and minerals.</li>
- </ul>
- </div>
- <div class="card">
- <div class="card-title"><span class="icon">🥗</span> Product Search Cards</div>
- <div style="margin-top: 1rem; border-top: 1px solid var(--border-color); padding-top: 1rem;">
- <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom: 0.8rem;">
- <strong>Unpasteurized Brie</strong>
- <span class="badge badge-red">High Risk</span>
- </div>
- <p style="font-size: 0.85rem; color: var(--text-secondary); margin-bottom: 1rem;">
- Listeria Risk: Avoid raw/unpasteurized soft cheeses during pregnancy.
- </p>
- <div style="display:flex; justify-content:space-between; align-items:center;">
- <strong>Raw Spinach</strong>
- <span class="badge badge-green">Recommended</span>
- </div>
- <p style="font-size: 0.85rem; color: var(--text-secondary);">
- High Iron & Folate: Encourages fetal cell growth.
- </p>
- </div>
- </div>
- </div>
- </div>
- <div class="slide-footer">
- <span>Local Food AI - User Presentation</span>
- <span>4 / 9</span>
- </div>
- </div>
- <!-- Slide 5: Plate Builder -->
- <div class="slide">
- <div class="slide-header">
- <span class="tag">Plate Formulation</span>
- <span class="title-badge">MY PLATE BUILDER</span>
- </div>
- <div class="slide-body">
- <h2 class="slide-title">Tab 2: My Plate Builder & Portion Parser</h2>
- <div class="slide-grid-2">
- <div>
- <ul>
- <li><strong>Natural Unit Parser</strong>: Clinicians can enter quantities in plain English (e.g. `1.5 cups`, `2 tablespoons`).</li>
- <li><strong>Density Conversions</strong>: Converts volume measurements into metric grams based on food density maps.</li>
- <li><strong>Cumulative Totals</strong>: Displays real-time compound macro updates (Proteins, Carbs, Fats).</li>
- </ul>
- </div>
- <div class="card">
- <div class="card-title"><span class="icon">📊</span> Macro intake vs Thresholds</div>
- <div style="margin-top: 1rem; display:flex; flex-direction:column; gap: 0.6rem;">
- <div>
- <div style="display:flex; justify-content:space-between; font-size:0.8rem; margin-bottom:0.2rem;">
- <span>Protein (70g Target)</span>
- <span>52g (74%)</span>
- </div>
- <div style="width:100%; height:8px; background:#222; border-radius:4px; overflow:hidden;">
- <div style="width:74%; height:100%; background:var(--primary-accent);"></div>
- </div>
- </div>
- <div>
- <div style="display:flex; justify-content:space-between; font-size:0.8rem; margin-bottom:0.2rem;">
- <span>Sodium (2000mg Limit)</span>
- <span>420mg (21%)</span>
- </div>
- <div style="width:100%; height:8px; background:#222; border-radius:4px; overflow:hidden;">
- <div style="width:21%; height:100%; background:var(--secondary-accent);"></div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="slide-footer">
- <span>Local Food AI - User Presentation</span>
- <span>5 / 9</span>
- </div>
- </div>
- <!-- Slide 6: Consultation Chat -->
- <div class="slide">
- <div class="slide-header">
- <span class="tag">Interactive AI</span>
- <span class="title-badge">CONSULTATION CHAT</span>
- </div>
- <div class="slide-body">
- <h2 class="slide-title">Tab 3: Clinician Consultation Portal</h2>
- <div class="slide-grid-2">
- <div>
- <ul>
- <li><strong>Client Profile Dropdown</strong>: Select medical conditions (Diabetes, Anemia, Hypertension, Pregnancy).</li>
- <li><strong>Verified database queries (RAG)</strong>: The local model queries local food data first to ensure factual responses.</li>
- <li><strong>Chain-of-Thought Explanation</strong>: Explains details step-by-step to help clinicians verify reasoning path safety.</li>
- </ul>
- </div>
- <div class="card" style="background:#161b22; font-family:var(--font-mono); font-size:0.85rem;">
- <div style="color:var(--primary-accent); margin-bottom:0.4rem;">> Can my diabetic client eat dates?</div>
- <div style="color:var(--text-secondary); margin-bottom:0.4rem;"><thought>
- Checking glycaemic index... Dates contain ~66g sugar per 100g. High GI load. Injected profile is Diabetes.
- </thought></div>
- <div style="color:#fff;">Dates are high in simple sugars (GI ~103). Recommend limiting portion to <20g and pairing with almonds to slow absorption.</div>
- </div>
- </div>
- </div>
- <div class="slide-footer">
- <span>Local Food AI - User Presentation</span>
- <span>6 / 9</span>
- </div>
- </div>
- <!-- Slide 7: Meal Planner -->
- <div class="slide">
- <div class="slide-header">
- <span class="tag">Diet Plans</span>
- <span class="title-badge">AI MEAL PLANNER</span>
- </div>
- <div class="slide-body">
- <h2 class="slide-title">Tab 4: Automated Clinical Meal Planner</h2>
- <div class="slide-grid-2">
- <div>
- <ul>
- <li><strong>Daily Caloric Targets</strong>: Input targets (e.g. `2000 kcal`) to scale portion recommendations.</li>
- <li><strong>Diet constraints integration</strong>: Enter restrictions (e.g. Halal, Vegan, Low-Fat, Kosher).</li>
- <li><strong>Printable Grid output</strong>: Formats the entire breakdown (Breakfast, Lunch, Dinner) into clean tables.</li>
- </ul>
- </div>
- <table style="width: 100%; border-collapse: collapse; font-size: 0.85rem; text-align: left;">
- <thead>
- <tr style="border-bottom: 1px solid var(--border-color); color:#fff;">
- <th style="padding: 0.5rem 0;">Meal</th>
- <th style="padding: 0.5rem 0;">Proposed Food</th>
- <th style="padding: 0.5rem 0;">Kcal</th>
- </tr>
- </thead>
- <tbody>
- <tr style="border-bottom: 1px dashed var(--border-color);">
- <td style="padding: 0.5rem 0;">Breakfast</td>
- <td style="padding: 0.5rem 0; color:var(--primary-accent);">Oatmeal with Walnuts & Bananas</td>
- <td style="padding: 0.5rem 0;">450</td>
- </tr>
- <tr style="border-bottom: 1px dashed var(--border-color);">
- <td style="padding: 0.5rem 0;">Lunch</td>
- <td style="padding: 0.5rem 0; color:var(--primary-accent);">Quinoa & Roasted Veggie Salad</td>
- <td style="padding: 0.5rem 0;">650</td>
- </tr>
- <tr>
- <td style="padding: 0.5rem 0;">Dinner</td>
- <td style="padding: 0.5rem 0; color:var(--primary-accent);">Lentil Dahl with Brown Rice</td>
- <td style="padding: 0.5rem 0;">750</td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- <div class="slide-footer">
- <span>Local Food AI - User Presentation</span>
- <span>7 / 9</span>
- </div>
- </div>
- <!-- Slide 8: Privacy Guarantees -->
- <div class="slide">
- <div class="slide-header">
- <span class="tag">Security</span>
- <span class="title-badge">PRIVACY GUARANTEED</span>
- </div>
- <div class="slide-body">
- <h2 class="slide-title">How Your Patient Data is Protected</h2>
- <div class="slide-grid-2">
- <div>
- <ul>
- <li class="warning-li"><strong>No External API Transmissions</strong>: Patient data stays locally in memory. Zero external sharing.</li>
- <li><strong>Anonymous SearXNG Meta-Search</strong>: External searches are stripped of cookies and clinic source tags.</li>
- <li><strong>Isolated Networks</strong>: System nodes run in private networks, blocking external access.</li>
- </ul>
- </div>
- <div class="card" style="background: rgba(52, 211, 153, 0.05); border-color: rgba(52, 211, 153, 0.2);">
- <div class="card-title" style="color: var(--primary-accent);"><span class="icon">🔒</span> Hospital-Grade Data Security</div>
- <div class="card-desc" style="color: var(--text-primary);">
- All processing occurs inside your facility's firewall. Local databases and local AI engines guarantee complete privacy compliance.
- </div>
- </div>
- </div>
- </div>
- <div class="slide-footer">
- <span>Local Food AI - User Presentation</span>
- <span>8 / 9</span>
- </div>
- </div>
- <!-- Slide 9: User Workflow Walkthrough -->
- <div class="slide">
- <div class="slide-header">
- <span class="tag">Application Use</span>
- <span class="title-badge">WORKFLOW STEPS</span>
- </div>
- <div class="slide-body">
- <h2 class="slide-title">Step-by-Step Clinical Workflow</h2>
- <div class="slide-grid-3">
- <div class="card">
- <div class="card-title">1. Patient Profile</div>
- <div class="card-desc">Select active health restrictions and medical conditions in the sidebar selector.</div>
- </div>
- <div class="card">
- <div class="card-title">2. Build Diet Plate</div>
- <div class="card-desc">Search foods, add to plate, and adjust portions using natural volumes.</div>
- </div>
- <div class="card">
- <div class="card-title">3. Consult AI</div>
- <div class="card-desc">Generate meal plans, check safety flags, and view the AI's clinical reasoning.</div>
- </div>
- </div>
- </div>
- <div class="slide-footer">
- <span>Local Food AI - User Presentation</span>
- <span>9 / 9</span>
- </div>
- </div>
- </div>
- </div>
- <!-- Navigation Controls -->
- <div class="controls">
- <button class="nav-btn" id="prevBtn" aria-label="Previous slide">←</button>
- <div class="progress-bar-container">
- <div class="progress-bar" id="progress"></div>
- </div>
- <span class="slide-counter" id="counter">Slide 1 of 9</span>
- <button class="nav-btn" id="nextBtn" aria-label="Next slide">→</button>
- </div>
- <script>
- let currentSlide = 0;
- const slides = document.querySelectorAll('.slide');
- const totalSlides = slides.length;
- const prevBtn = document.getElementById('prevBtn');
- const nextBtn = document.getElementById('nextBtn');
- const progress = document.getElementById('progress');
- const counter = document.getElementById('counter');
- function updateSlides() {
- slides.forEach((slide, idx) => {
- slide.classList.remove('active', 'prev', 'next');
- if (idx === currentSlide) {
- slide.classList.add('active');
- } else if (idx < currentSlide) {
- slide.classList.add('prev');
- } else {
- slide.classList.add('next');
- }
- });
- // Update progress bar
- const pct = ((currentSlide + 1) / totalSlides) * 100;
- progress.style.width = `${pct}%`;
- // Update slide counter
- counter.innerText = `Slide ${currentSlide + 1} of ${totalSlides}`;
- // Disable buttons at bounds
- prevBtn.disabled = currentSlide === 0;
- nextBtn.disabled = currentSlide === totalSlides - 1;
- }
- prevBtn.addEventListener('click', () => {
- if (currentSlide > 0) {
- currentSlide--;
- updateSlides();
- }
- });
- nextBtn.addEventListener('click', () => {
- if (currentSlide < totalSlides - 1) {
- currentSlide++;
- updateSlides();
- }
- });
- // Key bindings
- document.addEventListener('keydown', (e) => {
- if (e.key === 'ArrowRight' || e.key === ' ') {
- if (currentSlide < totalSlides - 1) {
- currentSlide++;
- updateSlides();
- }
- } else if (e.key === 'ArrowLeft') {
- if (currentSlide > 0) {
- currentSlide--;
- updateSlides();
- }
- }
- });
- updateSlides();
- </script>
- </body>
- </html>
|