diff options
Diffstat (limited to 'app/static')
| -rw-r--r-- | app/static/css/style.css | 369 | ||||
| -rw-r--r-- | app/static/js/main.js | 18 |
2 files changed, 387 insertions, 0 deletions
diff --git a/app/static/css/style.css b/app/static/css/style.css new file mode 100644 index 0000000..7167e05 --- /dev/null +++ b/app/static/css/style.css @@ -0,0 +1,369 @@ +/* ── Variables ────────────────────────────────────────────────────────────── */ +:root { + --primary: #b5451b; + --primary-hover: #8c3414; + --accent: #2d6a4f; + --bg: #f7f4f0; + --card-bg: #ffffff; + --text: #1a1a1a; + --muted: #6b7280; + --border: #e5e0d8; +} + +/* ── Base ─────────────────────────────────────────────────────────────────── */ +body { + background: var(--bg); + color: var(--text); + font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; +} + +/* ── Navbar ───────────────────────────────────────────────────────────────── */ +.navbar { + background: #1c1c1c !important; + border-bottom: 2px solid var(--primary); +} + +.navbar-brand { + font-size: 1.1rem; + letter-spacing: 0.3px; +} + +.nav-link { + color: #ccc !important; + border-radius: 6px; + padding: 0.35rem 0.75rem !important; + transition: all 0.15s; +} + +.nav-link:hover, .nav-link.active { + color: #fff !important; + background: rgba(255,255,255,0.1); +} + +/* ── Buttons ──────────────────────────────────────────────────────────────── */ +.btn-primary { + background: var(--primary); + border-color: var(--primary); +} +.btn-primary:hover { + background: var(--primary-hover); + border-color: var(--primary-hover); +} + +/* ── Stat cards ───────────────────────────────────────────────────────────── */ +.stat-card { + background: var(--card-bg); + border: 1px solid var(--border); + border-radius: 12px; + padding: 1.25rem; + text-align: center; + box-shadow: 0 1px 3px rgba(0,0,0,0.06); +} + +.stat-number { + font-size: 2rem; + font-weight: 700; + color: var(--primary); + line-height: 1; +} + +.stat-label { + font-size: 0.8rem; + color: var(--muted); + margin-top: 0.25rem; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +/* ── Week table (dashboard + plan) ───────────────────────────────────────── */ +.week-table, .plan-table { + font-size: 0.85rem; +} + +.week-table td, .plan-table td { + vertical-align: middle; +} + +.meal-type-label { + background: #f9f6f2; + text-align: right; + padding-right: 1rem !important; + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 0.5px; + color: var(--muted); +} + +.plan-cell { + padding: 6px !important; + min-width: 130px; +} + +.today-col { + background: rgba(181, 69, 27, 0.06) !important; +} + +.plan-entry, .planned-meal { + font-size: 0.82rem; +} + +.meal-recipe-name { + font-weight: 600; + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.meal-macros { + font-size: 0.72rem; + color: var(--muted); + margin-top: 2px; +} + +.add-meal-btn { + background: transparent; + border: 1px dashed var(--border); + color: #aaa; + transition: all 0.15s; + padding: 6px; + font-size: 1.1rem; +} + +.add-meal-btn:hover { + border-color: var(--primary); + color: var(--primary); + background: rgba(181,69,27,0.04); +} + +.empty-slot { + color: #ccc; + font-size: 1.2rem; +} + +/* ── Recipe cards ─────────────────────────────────────────────────────────── */ +.recipe-card { + border: 1px solid var(--border) !important; + border-radius: 12px !important; + transition: box-shadow 0.2s, transform 0.2s; +} + +.recipe-card:hover { + box-shadow: 0 4px 16px rgba(0,0,0,0.12) !important; + transform: translateY(-2px); +} + +/* ── Cuisine pills ────────────────────────────────────────────────────────── */ +.cuisine-pill { + display: inline-block; + background: #f0ebe3; + color: #5a4a3a; + font-size: 0.72rem; + padding: 2px 10px; + border-radius: 20px; + font-weight: 600; + letter-spacing: 0.3px; +} + +.cuisine-badge { + font-size: 1rem; +} + +/* ── Nutrition badges ─────────────────────────────────────────────────────── */ +.nutri-badge { + display: inline-flex; + align-items: center; + gap: 4px; + font-size: 0.72rem; + color: var(--muted); + background: #f5f5f5; + padding: 2px 8px; + border-radius: 20px; + white-space: nowrap; +} + +.nutrition-row { + display: flex; + flex-wrap: wrap; + gap: 4px; +} + +/* ── Info badges (recipe detail) ──────────────────────────────────────────── */ +.info-badge { + display: inline-flex; + align-items: center; + gap: 5px; + font-size: 0.82rem; + padding: 4px 12px; + border-radius: 20px; + font-weight: 500; +} + +/* ── Ingredient list ──────────────────────────────────────────────────────── */ +.ingredient-list { + list-style: none; + padding: 0; + margin: 0; +} + +.ingredient-list li { + display: flex; + align-items: baseline; + gap: 8px; + padding: 5px 0; + border-bottom: 1px solid #f0ece6; + font-size: 0.9rem; +} + +.ingredient-list li:last-child { + border-bottom: none; +} + +.ing-qty { + min-width: 80px; + color: var(--primary); + font-weight: 600; + font-size: 0.85rem; + flex-shrink: 0; +} + +/* ── Instructions ─────────────────────────────────────────────────────────── */ +.instructions-block { + display: flex; + flex-direction: column; + gap: 12px; +} + +.instruction-step { + padding: 10px 14px; + background: #f9f6f2; + border-left: 3px solid var(--primary); + border-radius: 0 8px 8px 0; + font-size: 0.9rem; + line-height: 1.5; +} + +/* ── Shopping list ────────────────────────────────────────────────────────── */ +.shopping-item { + transition: background 0.15s; +} + +.shopping-item.checked { + background: #f8fdf8; +} + +.shopping-item.checked .check-label { + text-decoration: line-through; + color: var(--muted); +} + +.shopping-item.checked .ing-qty { + color: var(--muted); +} + +.source-text { + font-style: italic; +} + +/* ── Quick link cards ─────────────────────────────────────────────────────── */ +.quick-link-card { + display: flex; + align-items: center; + gap: 12px; + background: var(--card-bg); + border: 1px solid var(--border); + border-radius: 10px; + padding: 1rem 1.25rem; + text-decoration: none; + color: var(--text); + font-weight: 500; + transition: all 0.15s; + font-size: 0.9rem; +} + +.quick-link-card:hover { + border-color: var(--primary); + background: #fdf8f5; + color: var(--primary); + box-shadow: 0 2px 8px rgba(181,69,27,0.1); +} + +/* ── Footer ───────────────────────────────────────────────────────────────── */ +footer { + border-top: 1px solid var(--border); + background: var(--bg); +} + +/* ── AI Chat ──────────────────────────────────────────────────────────────── */ +.chat-window { + background: #f9f6f2; + border: 1px solid var(--border); + border-radius: 12px; + min-height: 200px; +} + +.message { + display: flex; + margin-bottom: 12px; +} + +.message-user { + justify-content: flex-end; +} + +.message-assistant { + justify-content: flex-start; +} + +.message-bubble { + max-width: 80%; + padding: 10px 14px; + border-radius: 12px; + font-size: 0.9rem; + line-height: 1.55; +} + +.message-user .message-bubble { + background: var(--primary); + color: #fff; + border-bottom-right-radius: 4px; +} + +.message-assistant .message-bubble { + background: #ffffff; + border: 1px solid var(--border); + border-bottom-left-radius: 4px; +} + +.recipe-added-card { + background: #f0fdf4 !important; + border-color: #86efac !important; +} + +.chat-input-area textarea { + resize: none; + border-radius: 10px 0 0 10px; + font-size: 0.9rem; +} + +.chat-input-area .btn { + border-radius: 0 10px 10px 0; +} + +/* ── Star rating ─────────────────────────────────────────────────────────── */ +.star-rating .star { + color: #f59e0b; + font-size: 1.25rem; + transition: transform 0.1s; +} +.star-rating .star[style*="cursor:pointer"]:hover { + transform: scale(1.2); +} + +/* ── Print ────────────────────────────────────────────────────────────────── */ +@media print { + .no-print, nav, footer, button, .btn { display: none !important; } + body { background: white; } + .card { border: 1px solid #ddd !important; box-shadow: none !important; } + .shopping-item.checked .check-label { text-decoration: none; color: #000; } +} diff --git a/app/static/js/main.js b/app/static/js/main.js new file mode 100644 index 0000000..ed1147b --- /dev/null +++ b/app/static/js/main.js @@ -0,0 +1,18 @@ +// Global JSON fetch helper — redirects to /login on 401 +async function api(url, options = {}) { + const res = await fetch(url, { + headers: {'Content-Type': 'application/json'}, + ...options, + }); + if (res.status === 401) { + window.location.href = '/login?next=' + encodeURIComponent(window.location.pathname); + return null; + } + return res; +} + +document.addEventListener('DOMContentLoaded', () => { + document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(el => + new bootstrap.Tooltip(el) + ); +}); |
