A React + TypeScript + Vite web app for calculating pizza and bread dough ingredients with presets for famous styles, adjustable hydration, yeast type, and oven temperature.
Repository: https://github.com/Scallywer/pizza-calc
- Multiple pizza style presets (Neapolitan, New York, Detroit, Sicilian, Roman, Focaccia, Sourdough, Grandma)
- Adjustable hydration, yeast type, and fermentation parameters
- Automatic yeast scaling based on target rise time and temperature
- Size by total dough weight or pizza diameter
- Oven temperature capping and bake time estimation
- Settings persisted in browser localStorage
npm install
npm run devnpm run builddocker-compose up -dNote: After the first GitHub Actions run, your image will be at ghcr.io/scallywer/pizza-calc:latest
Option 1: Make package public (easiest)
- Go to https://github.com/Scallywer/pizza-calc/packages
- Click on the package → Package settings → Change visibility to Public
- No authentication needed
Option 2: Use private package (requires auth)
Create a Personal Access Token (PAT) with read:packages permission:
docker login ghcr.io -u Scallywer
# Enter your PAT when promptedThen use the production compose file:
docker-compose -f docker-compose.prod.yml up -dThe app will be available on port 8080 (or whatever port you configure).
Add this to your HAProxy config to route traffic to the container:
frontend web_frontend
bind *:80
bind *:443 ssl crt /path/to/cert.pem
# Pizza calculator
acl is_pizza path_beg /pizza
use_backend pizza_backend if is_pizza
backend pizza_backend
server pizza-dough-calc localhost:8080 check
# Or if using Docker network:
# server pizza-dough-calc pizza-dough-calc:80 checkOr if you want a subdomain:
frontend web_frontend
bind *:80
bind *:443 ssl crt /path/to/cert.pem
acl is_pizza hdr(host) -i pizza.yourdomain.com
use_backend pizza_backend if is_pizza
backend pizza_backend
server pizza-dough-calc localhost:8080 checkManual Update:
docker-compose down
docker-compose pull
docker-compose up -dAutomatic Updates (Recommended for Homelab):
Option 1: Use Watchtower (Auto-updates all containers)
# Install watchtower once
docker run -d \
--name watchtower \
--restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
--interval 3600 \
pizza-dough-calcOption 2: GitHub Actions + Webhook (Update on commit)
- The GitHub Actions workflow automatically builds and pushes to
ghcr.io - Set up a webhook receiver on your homelab to pull and restart on new images
- Or use a scheduled cron job to check for updates
Option 3: Update script (included in repo)
# Linux/Mac
chmod +x update.sh
./update.sh
# Windows PowerShell
.\update.ps1Set up a cron job (Linux) or Task Scheduler (Windows) to run automatically:
# Linux cron example (check every hour)
0 * * * * /path/to/pizza-calc/update.sh >> /var/log/pizza-calc-update.log 2>&1This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- @vitejs/plugin-react uses Babel (or oxc when used in rolldown-vite) for Fast Refresh
- @vitejs/plugin-react-swc uses SWC for Fast Refresh
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see this documentation.
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,
// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])You can also install eslint-plugin-react-x and eslint-plugin-react-dom for React-specific lint rules:
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])