A progressive web app for tracking daily macronutrient intake. Built with Vue 3, Vuetify, and IndexedDB for fully offline, local-first usage — no account or server required.
- Log food entries via three methods: manual input, saved food items (with adjustable servings), or meal templates
- View real-time progress bars for calories, protein, carbs, and fat against your daily goals
- Click any macro progress bar to see a breakdown of which foods contributed what percentage, sorted by contribution
- See percentage completion and remaining macros at a glance
- Navigate between days with previous/next buttons to review or edit past entries
- Delete individual entries from the daily log
- Optionally connect your OpenAI API key to estimate macros from a food description
- Uses GPT-4o-mini for quick, low-cost estimations
- API key is stored locally in your browser and never sent to any server other than OpenAI
- Take a picture of a food product's nutrition label (or pick an existing photo) from the Add Entry and New/Edit Food dialogs
- GPT-4o-mini vision reads the label and auto-fills calories, protein, carbs, sugar, fiber, and fat
- Handles US and EU layouts, kJ→kcal conversion, per-100g vs per-serving columns, and non-English labels
- Also fills serving size and unit when readable on the label
- Image is resized to 1024px client-side before being sent to keep cost and bandwidth low
- Paste a restaurant menu and get AI-powered recommendations for the best soup and main course to fit your remaining daily macros
- Shows your remaining macro budget for context
- Displays estimated macros and reasoning for each recommendation
- Add recommended items directly to your daily log with one tap
- Get AI-powered healthy snack suggestions based on your remaining daily macro budget
- Each suggestion includes portion size, estimated macros, and reasoning for why it fits your goals
- Add any suggested snack directly to your daily log with one tap
- Create a personal library of food items with serving size, unit (g, oz, cup, etc.), and macro values
- Build meal templates that store total macros for frequently eaten combinations
- Search and filter across saved foods and meals
- View daily macro history over 7, 14, or 30 day ranges
- Interactive line chart with toggleable macro series and goal reference lines
- Weekly averages calculated from days with logged entries
- Expandable daily breakdown showing all entries per day
- Set custom daily targets for calories, protein, carbs, and fat
- Defaults to 2000 cal / 150g protein / 250g carbs / 65g fat
- Goals persist across sessions
- Export all data (foods, meals, entries, goals) as a timestamped JSON file
- Import previously exported data with validation
- Clear all data with confirmation prompt
- Installable on mobile and desktop — runs as a standalone app
- Full offline functionality via service worker caching
- Auto-updates when a new version is deployed
- Toggle between light and dark themes from settings
- Preference persists across sessions
| Layer | Technology |
|---|---|
| Framework | Vue 3 (Composition API) + TypeScript |
| UI | Vuetify 4 + Material Design Icons |
| State | Pinia |
| Routing | Vue Router |
| Database | Dexie (IndexedDB) |
| Charts | Chart.js + vue-chartjs |
| Build | Vite + vite-plugin-pwa |
| IDs | UUIDv7 |
# Install dependencies
pnpm install
# Start dev server
pnpm dev
# Build for production
pnpm build
# Lint
pnpm lintAlternatively, if you use Nix, you can run commands via the project's dev shell:
nix develop -c pnpm devTwo suites, split by what they need to run.
Unit tests — Vitest, jsdom, no build. The stores, the date and macro helpers,
and one smoke test that mounts the app shell. They live next to what they cover,
in src/**/__tests__/, and are what to reach for first.
nix develop -c pnpm test # run once
nix develop -c pnpm test:watch # re-run on changeEnd-to-end tests — Playwright, driving the production build in a real
browser. These cover what only a browser can show: the service worker with the
network cut, and data written and read back through IndexedDB. The browsers come
from the playwright nix shell rather than playwright install, so CI and a dev
machine drive the same binary.
nix develop .#playwright -c pnpm test:e2eSee e2e-tests/README.md for the details — the shared
preview port, the @playwright/test pin, and the conventions the specs follow.
CI runs the unit tests on every push (.github/workflows/build.yml) and the e2e
suite on pull requests and main (.github/workflows/e2e-tests.yml).
src/
├── pages/ # Route-level page components
├── components/ # UI components organized by feature
│ ├── daily/ # Daily tracking (progress, entries, add dialog, day navigation)
│ ├── history/ # Charts, averages, daily breakdown
│ ├── meals/ # Food and meal CRUD
│ ├── settings/ # Goals, theme, data management, AI config
│ └── layout/ # Bottom navigation
├── stores/ # Pinia stores (dailyLog, history, foods, app)
├── services/ # External API integration (OpenAI)
├── db/ # Dexie database setup
├── utils/ # Date helpers
├── types/ # TypeScript interfaces
├── plugins/ # Vuetify, Pinia, Router config
└── main.ts # App entry point