diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 0ed3b12..c470e17 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -400,6 +400,27 @@ function AppContent() { return () => document.removeEventListener("keydown", handleEscape); }, [selectedMed, showImageLightbox, selectedUser, showProfile, showShareDialog, showEditModal]); + // Prevent background scroll when modal is open + useEffect(() => { + const isModalOpen = selectedMed || selectedUser || showProfile || showShareDialog || showEditModal; + if (isModalOpen) { + const scrollY = window.scrollY; + document.body.classList.add('modal-open'); + document.body.style.top = `-${scrollY}px`; + } else { + const scrollY = document.body.style.top; + document.body.classList.remove('modal-open'); + document.body.style.top = ''; + if (scrollY) { + window.scrollTo(0, parseInt(scrollY || '0', 10) * -1); + } + } + return () => { + document.body.classList.remove('modal-open'); + document.body.style.top = ''; + }; + }, [selectedMed, selectedUser, showProfile, showShareDialog, showEditModal]); + // Check if settings have changed const settingsChanged = settings.emailEnabled !== savedSettings.emailEnabled || settings.notificationEmail !== savedSettings.notificationEmail || @@ -1391,8 +1412,8 @@ function AppContent() {
{t('medications.details.total')}: {med.count} {t('common.pills')}
- - + +
@@ -1500,7 +1521,7 @@ function AppContent() {
{form.blisters.length > 1 && ( - + )} ))} @@ -1516,7 +1537,7 @@ function AppContent() { return (
{currentMed.name} - +
); } @@ -1534,7 +1555,7 @@ function AppContent() { return (
Preview - +
); } @@ -2229,11 +2250,11 @@ function AppContent() { {t('common.close')}
- {selectedMed.blisters.length > 0 && ( - )} @@ -2439,7 +2460,7 @@ function AppContent() { {t('form.medicationImage')}
{currentMed.name} - +
); @@ -2479,7 +2500,7 @@ function AppContent() { {t('form.blisters.startTime')} setBlisterValue(idx, "startTime", e.target.value)} /> - {form.blisters.length > 1 && } + {form.blisters.length > 1 && } ))} diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 6e7fcca..a133d59 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -21,6 +21,14 @@ --warning: #fcd34d; --warning-bg: rgba(252, 211, 77, 0.12); --shadow: rgba(0, 0, 0, 0.25); + /* Button Design System */ + --btn-radius: 10px; + --btn-radius-round: 50%; + --btn-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); + --btn-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.2); + --btn-primary-bg: var(--accent); + --btn-primary-hover: #3d94ff; + --btn-ghost-hover: rgba(255, 255, 255, 0.08); } [data-theme="light"] { @@ -44,6 +52,12 @@ --warning: #f59e0b; --warning-bg: rgba(245, 158, 11, 0.1); --shadow: rgba(0, 0, 0, 0.08); + /* Button Design System */ + --btn-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + --btn-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.12); + --btn-primary-bg: var(--accent); + --btn-primary-hover: #1d4ed8; + --btn-ghost-hover: rgba(0, 0, 0, 0.06); } * { box-sizing: border-box; } @@ -58,6 +72,13 @@ body { transition: background 200ms ease, color 200ms ease; } +body.modal-open { + overflow: hidden !important; + position: fixed; + width: 100%; + height: 100%; +} + .page { max-width: 1200px; margin: 0 auto; @@ -87,7 +108,7 @@ body { .icon-btn { width: 40px; height: 40px; - border-radius: 50%; + border-radius: var(--btn-radius-round); background: transparent; border: none; cursor: pointer; @@ -95,20 +116,20 @@ body { display: flex; align-items: center; justify-content: center; - transition: transform 150ms ease, background 150ms ease; + transition: background 150ms ease, opacity 150ms ease; padding: 0; opacity: 0.7; + box-shadow: none; } .icon-btn:hover { - transform: scale(1.1); - background: rgba(255, 255, 255, 0.1); + background: var(--btn-ghost-hover); opacity: 1; } .icon-btn.active { opacity: 1; background: rgba(47, 134, 246, 0.15); } -[data-theme="light"] .icon-btn:hover { background: rgba(0, 0, 0, 0.08); } +[data-theme="light"] .icon-btn:hover { background: var(--btn-ghost-hover); } [data-theme="light"] .icon-btn.active { background: rgba(47, 134, 246, 0.12); } .hero-title { display: flex; align-items: center; gap: 1rem; } @@ -211,9 +232,9 @@ body { border-color: var(--accent-light); } -.pill { border: 1px solid var(--accent); color: var(--text-muted); background: var(--accent-bg); padding: 0.35rem 0.7rem; border-radius: 999px; font-size: 0.85rem; transition: all 150ms ease; } +.pill { border: 1px solid var(--accent); color: var(--text-muted); background: var(--accent-bg); padding: 0.35rem 0.7rem; border-radius: 999px; font-size: 0.85rem; transition: background 150ms ease, border-color 150ms ease; } .pill.clickable { cursor: pointer; } -.pill.clickable:hover { filter: brightness(1.15); transform: scale(1.02); } +.pill.clickable:hover { filter: brightness(1.1); } .pill.success { border-color: var(--success); background: var(--success-bg); color: var(--success); } .pill.neutral { border-color: var(--border-secondary); background: rgba(255, 255, 255, 0.04); color: var(--text-muted); } [data-theme=\"light\"] .pill.neutral { background: rgba(0, 0, 0, 0.04); } @@ -339,27 +360,85 @@ body { button { padding: 0.7rem 1.25rem; - border-radius: 8px; + border-radius: var(--btn-radius); border: none; - background: linear-gradient(135deg, var(--accent), var(--accent-light)); + background: var(--btn-primary-bg); color: white; cursor: pointer; font-weight: 600; font-size: 0.9rem; - transition: transform 120ms ease, box-shadow 120ms ease, opacity 120ms ease; + box-shadow: var(--btn-shadow); + transition: background 150ms ease, box-shadow 150ms ease, opacity 150ms ease; +} +button:hover { + background: var(--btn-primary-hover); +} +button:active { + box-shadow: var(--btn-shadow); +} + +/* Secondary button (Edit, etc.) */ +button.secondary { + background: var(--bg-tertiary); + color: var(--text-primary); + border: 1px solid var(--border-secondary); +} +button.secondary:hover { + background: var(--bg-secondary); + border-color: var(--accent); +} +[data-theme="light"] button.secondary { + background: var(--bg-tertiary); +} +[data-theme="light"] button.secondary:hover { + background: var(--bg-secondary); +} + +/* Ghost button (Cancel, etc.) */ +button.ghost { + background: transparent; + border: 1px solid var(--border-secondary); + color: var(--text-muted); + box-shadow: none; +} +button.ghost:hover { + background: var(--btn-ghost-hover); +} +[data-theme="light"] button.ghost:hover { + background: var(--btn-ghost-hover); +} + +/* Danger button (Delete, etc.) */ +button.danger { + background: var(--danger); + color: white; + border: none; +} +button.danger:hover { + background: #dc2626; +} +[data-theme="light"] button.danger { + background: var(--danger); +} +[data-theme="light"] button.danger:hover { + background: #dc2626; +} + +/* Legacy ghost danger (keep for compatibility) */ +button.ghost.danger { + background: transparent; + border: 1px solid rgba(239, 68, 68, 0.4); + color: var(--danger); + box-shadow: none; +} +button.ghost.danger:hover { + background: var(--danger-bg); } -button:hover { transform: translateY(-1px); box-shadow: 0 8px 20px rgba(47, 134, 246, 0.35); } -button:active { transform: translateY(0); } -button.ghost { background: transparent; border: 1px solid var(--border-secondary); color: var(--text-muted); box-shadow: none; } -button.ghost:hover { background: rgba(255, 255, 255, 0.06); transform: none; } -[data-theme=\"light\"] button.ghost:hover { background: rgba(0, 0, 0, 0.04); } -button.ghost.danger { border-color: rgba(239, 68, 68, 0.4); color: var(--danger); } -button.ghost.danger:hover { background: var(--danger-bg); } input, select, textarea { width: 100%; padding: 0.7rem 0.85rem; - border-radius: 8px; + border-radius: var(--btn-radius); border: 1px solid var(--border-secondary); background: var(--bg-input); color: var(--text-primary); @@ -379,7 +458,7 @@ textarea { .static-value { padding: 0.7rem 0.85rem; - border-radius: 8px; + border-radius: var(--btn-radius); background: var(--accent-bg); border: 1px solid var(--accent); color: var(--text-primary); @@ -404,12 +483,13 @@ textarea { padding: 0.75rem 1rem; background: var(--bg-tertiary); border: 1px dashed var(--border-primary); - border-radius: 12px; + border-radius: var(--btn-radius); cursor: pointer; user-select: none; color: var(--text-secondary); font-size: 0.9rem; - transition: all 0.2s ease; + transition: background 150ms ease, border-color 150ms ease, color 150ms ease; + box-shadow: none; } .past-days-toggle:hover { background: var(--bg-secondary); @@ -623,14 +703,15 @@ textarea { height: 28px; min-height: 28px; padding: 0; - border-radius: 50%; + border-radius: var(--btn-radius-round); display: flex; align-items: center; justify-content: center; font-size: 0.9rem; cursor: pointer; - transition: all 0.15s ease; + transition: background 150ms ease, border-color 150ms ease, color 150ms ease; flex-shrink: 0; + box-shadow: none; } .dose-btn.take { @@ -642,7 +723,6 @@ textarea { .dose-btn.take:hover:not(:disabled) { background: var(--success); color: white; - transform: scale(1.1); } .dose-btn.take:disabled { @@ -667,7 +747,6 @@ textarea { background: var(--warning-bg); border-color: var(--warning); color: var(--warning); - transform: scale(1.1); } .time-row.taken { @@ -1417,7 +1496,9 @@ textarea { background: transparent; border: none; cursor: pointer; - transition: background 0.2s; + transition: background 150ms ease; + border-radius: var(--btn-radius); + box-shadow: none; } .channel-toggle:hover { @@ -1986,6 +2067,8 @@ textarea { z-index: 1000; padding: 2rem 1rem; animation: fadeIn 0.2s ease; + overflow-y: auto; + overscroll-behavior: contain; } @keyframes fadeIn { @@ -2016,7 +2099,7 @@ textarea { position: absolute; top: 1rem; right: 1rem; - background: rgba(255, 255, 255, 0.1); + background: var(--btn-ghost-hover); border: 1px solid var(--border-secondary); font-size: 1.2rem; color: var(--text-secondary); @@ -2029,17 +2112,21 @@ textarea { display: flex; align-items: center; justify-content: center; - border-radius: 50%; - transition: all 0.2s ease; + border-radius: var(--btn-radius-round); + transition: background 150ms ease, border-color 150ms ease, color 150ms ease; flex-shrink: 0; padding: 0; + box-shadow: none; } .modal-close:hover { - background: rgba(255, 255, 255, 0.2); + background: rgba(255, 255, 255, 0.15); border-color: var(--text-secondary); color: var(--text-primary); - transform: scale(1.1); +} + +[data-theme="light"] .modal-close:hover { + background: rgba(0, 0, 0, 0.1); } /* Universal Modal Footer */ @@ -2433,12 +2520,13 @@ textarea { display: flex; align-items: center; justify-content: center; - border-radius: 50%; - transition: background 0.2s; + border-radius: var(--btn-radius-round); + transition: background 150ms ease; + box-shadow: none; } .lightbox-close:hover { - background: rgba(255, 255, 255, 0.2); + background: rgba(255, 255, 255, 0.25); } .lightbox-image { @@ -3007,7 +3095,7 @@ h3 .reminder-icon.info-tooltip { height: 28px; min-width: 28px; min-height: 28px; - border-radius: 50%; + border-radius: var(--btn-radius-round); border: 2px solid var(--bg-secondary); background: var(--bg-tertiary); color: var(--text-primary); @@ -3017,7 +3105,8 @@ h3 .reminder-icon.info-tooltip { align-items: center; justify-content: center; padding: 0; - transition: all 0.15s ease; + transition: background 150ms ease, color 150ms ease; + box-shadow: none; } .avatar-btn:hover {