feat: US-007 - Frontend: Modal backdrop opacity and touch optimization
This commit is contained in:
@@ -52,7 +52,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
min-width: 44px;
|
min-width: 44px;
|
||||||
min-height: 36px;
|
min-height: 44px;
|
||||||
padding: var(--space-2);
|
padding: var(--space-2);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
@@ -358,8 +358,8 @@
|
|||||||
|
|
||||||
/* Compact check button */
|
/* Compact check button */
|
||||||
.habit-card-check-btn-compact {
|
.habit-card-check-btn-compact {
|
||||||
width: 32px;
|
width: 44px;
|
||||||
height: 32px;
|
height: 44px;
|
||||||
border: 2px solid var(--accent);
|
border: 2px solid var(--accent);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
@@ -408,6 +408,8 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
transition: all var(--transition-base);
|
transition: all var(--transition-base);
|
||||||
|
min-width: 44px;
|
||||||
|
min-height: 44px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.habit-card-action-btn:hover {
|
.habit-card-action-btn:hover {
|
||||||
@@ -484,7 +486,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background: rgba(0, 0, 0, 0.7);
|
background: rgba(0, 0, 0, 0.6);
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -530,6 +532,8 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
transition: all var(--transition-base);
|
transition: all var(--transition-base);
|
||||||
|
min-width: 44px;
|
||||||
|
min-height: 44px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-close:hover {
|
.modal-close:hover {
|
||||||
|
|||||||
@@ -1781,6 +1781,14 @@ def run_all_tests():
|
|||||||
test_icon_picker_chevron_rotation,
|
test_icon_picker_chevron_rotation,
|
||||||
test_icon_picker_search_autofocus,
|
test_icon_picker_search_autofocus,
|
||||||
test_typecheck_us006,
|
test_typecheck_us006,
|
||||||
|
# US-007 tests (Modal backdrop and touch optimization)
|
||||||
|
test_modal_backdrop_opacity,
|
||||||
|
test_filter_icon_buttons_44px,
|
||||||
|
test_compact_check_button_44px,
|
||||||
|
test_action_buttons_44px,
|
||||||
|
test_modal_close_button_44px,
|
||||||
|
test_all_interactive_elements_touch_friendly,
|
||||||
|
test_typecheck_us007,
|
||||||
]
|
]
|
||||||
|
|
||||||
print(f"\nRunning {len(tests)} frontend tests for US-002, US-003, US-004, US-005, US-006 through US-014...\n")
|
print(f"\nRunning {len(tests)} frontend tests for US-002, US-003, US-004, US-005, US-006 through US-014...\n")
|
||||||
@@ -2731,3 +2739,130 @@ def test_typecheck_us006():
|
|||||||
assert result.returncode == 0, f"Typecheck failed: {result.stderr}"
|
assert result.returncode == 0, f"Typecheck failed: {result.stderr}"
|
||||||
print("✓ Test 163 passed: Typecheck successful")
|
print("✓ Test 163 passed: Typecheck successful")
|
||||||
|
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# US-007: Modal backdrop opacity and touch optimization
|
||||||
|
# ========================================
|
||||||
|
|
||||||
|
def test_modal_backdrop_opacity():
|
||||||
|
"""Test 164: Modal backdrop uses rgba(0, 0, 0, 0.6)"""
|
||||||
|
habits_path = Path(__file__).parent.parent / 'habits.html'
|
||||||
|
html = habits_path.read_text()
|
||||||
|
|
||||||
|
# Find modal-overlay CSS
|
||||||
|
modal_overlay = html[html.find('.modal-overlay {'):html.find('.modal-overlay {') + 300]
|
||||||
|
assert 'background: rgba(0, 0, 0, 0.6)' in modal_overlay, "Modal backdrop should be rgba(0, 0, 0, 0.6)"
|
||||||
|
assert 'rgba(0, 0, 0, 0.7)' not in modal_overlay, "Should not use old opacity value 0.7"
|
||||||
|
|
||||||
|
print("✓ Test 164 passed: Modal backdrop opacity is 0.6")
|
||||||
|
|
||||||
|
def test_filter_icon_buttons_44px():
|
||||||
|
"""Test 165: Filter icon buttons have min-height 44px"""
|
||||||
|
habits_path = Path(__file__).parent.parent / 'habits.html'
|
||||||
|
html = habits_path.read_text()
|
||||||
|
|
||||||
|
# Find filter-icon-btn CSS
|
||||||
|
filter_btn = html[html.find('.filter-icon-btn {'):html.find('.filter-icon-btn {') + 400]
|
||||||
|
assert 'min-width: 44px' in filter_btn, "Filter icon buttons should have min-width 44px"
|
||||||
|
assert 'min-height: 44px' in filter_btn, "Filter icon buttons should have min-height 44px"
|
||||||
|
assert 'min-height: 36px' not in filter_btn, "Should not use old min-height value 36px"
|
||||||
|
|
||||||
|
print("✓ Test 165 passed: Filter icon buttons are 44x44px minimum")
|
||||||
|
|
||||||
|
def test_compact_check_button_44px():
|
||||||
|
"""Test 166: Compact check button is 44x44px"""
|
||||||
|
habits_path = Path(__file__).parent.parent / 'habits.html'
|
||||||
|
html = habits_path.read_text()
|
||||||
|
|
||||||
|
# Find habit-card-check-btn-compact CSS (base style, not mobile override)
|
||||||
|
check_btn_start = html.find('.habit-card-check-btn-compact {')
|
||||||
|
check_btn = html[check_btn_start:check_btn_start + 500]
|
||||||
|
assert 'width: 44px' in check_btn, "Compact check button should have width: 44px"
|
||||||
|
assert 'height: 44px' in check_btn, "Compact check button should have height: 44px"
|
||||||
|
assert 'width: 32px' not in check_btn, "Should not use old width value 32px"
|
||||||
|
assert 'height: 32px' not in check_btn, "Should not use old height value 32px"
|
||||||
|
|
||||||
|
print("✓ Test 166 passed: Compact check button is 44x44px")
|
||||||
|
|
||||||
|
def test_action_buttons_44px():
|
||||||
|
"""Test 167: Action buttons (edit/delete) have min 44x44px"""
|
||||||
|
habits_path = Path(__file__).parent.parent / 'habits.html'
|
||||||
|
html = habits_path.read_text()
|
||||||
|
|
||||||
|
# Find habit-card-action-btn CSS (base style, not in media query)
|
||||||
|
# Search for all occurrences
|
||||||
|
action_btn_matches = []
|
||||||
|
start = 0
|
||||||
|
while True:
|
||||||
|
idx = html.find('.habit-card-action-btn {', start)
|
||||||
|
if idx == -1:
|
||||||
|
break
|
||||||
|
action_btn_matches.append(idx)
|
||||||
|
start = idx + 1
|
||||||
|
|
||||||
|
# Get the base style (should be the second one, after mobile styles)
|
||||||
|
assert len(action_btn_matches) >= 2, "Should have at least 2 .habit-card-action-btn definitions"
|
||||||
|
base_style_idx = action_btn_matches[1] # Second occurrence is the base style
|
||||||
|
action_btn = html[base_style_idx:base_style_idx + 500]
|
||||||
|
|
||||||
|
assert 'min-width: 44px' in action_btn, "Action buttons should have min-width 44px in base style"
|
||||||
|
assert 'min-height: 44px' in action_btn, "Action buttons should have min-height 44px in base style"
|
||||||
|
|
||||||
|
print("✓ Test 167 passed: Action buttons have min 44x44px touch targets")
|
||||||
|
|
||||||
|
def test_modal_close_button_44px():
|
||||||
|
"""Test 168: Modal close button has min 44x44px"""
|
||||||
|
habits_path = Path(__file__).parent.parent / 'habits.html'
|
||||||
|
html = habits_path.read_text()
|
||||||
|
|
||||||
|
# Find modal-close CSS (base style, not in media query)
|
||||||
|
# Search for all occurrences
|
||||||
|
modal_close_matches = []
|
||||||
|
start = 0
|
||||||
|
while True:
|
||||||
|
idx = html.find('.modal-close {', start)
|
||||||
|
if idx == -1:
|
||||||
|
break
|
||||||
|
modal_close_matches.append(idx)
|
||||||
|
start = idx + 1
|
||||||
|
|
||||||
|
# Get the base style (second occurrence)
|
||||||
|
assert len(modal_close_matches) >= 2, "Should have at least 2 .modal-close definitions"
|
||||||
|
base_style_idx = modal_close_matches[1]
|
||||||
|
modal_close = html[base_style_idx:base_style_idx + 500]
|
||||||
|
|
||||||
|
assert 'min-width: 44px' in modal_close, "Modal close button should have min-width 44px in base style"
|
||||||
|
assert 'min-height: 44px' in modal_close, "Modal close button should have min-height 44px in base style"
|
||||||
|
|
||||||
|
print("✓ Test 168 passed: Modal close button has min 44x44px touch target")
|
||||||
|
|
||||||
|
def test_all_interactive_elements_touch_friendly():
|
||||||
|
"""Test 169: Verify all key interactive elements meet 44px minimum"""
|
||||||
|
habits_path = Path(__file__).parent.parent / 'habits.html'
|
||||||
|
html = habits_path.read_text()
|
||||||
|
|
||||||
|
# List of interactive elements that should have proper touch targets
|
||||||
|
elements = [
|
||||||
|
('.habit-card-check-btn-compact', 'Check button'),
|
||||||
|
('.habit-card-action-btn', 'Action buttons'),
|
||||||
|
('.filter-icon-btn', 'Filter icon buttons'),
|
||||||
|
('.modal-close', 'Modal close button'),
|
||||||
|
]
|
||||||
|
|
||||||
|
for selector, name in elements:
|
||||||
|
# Find in base styles (not just mobile)
|
||||||
|
assert f'{selector}' in html, f"{name} should exist"
|
||||||
|
# We've already tested these individually, this is a summary check
|
||||||
|
|
||||||
|
print("✓ Test 169 passed: All interactive elements have touch-friendly sizes")
|
||||||
|
|
||||||
|
def test_typecheck_us007():
|
||||||
|
"""Test 170: Typecheck passes after US-007 changes"""
|
||||||
|
result = subprocess.run(
|
||||||
|
['python3', '-m', 'py_compile', 'dashboard/api.py', 'dashboard/habits_helpers.py'],
|
||||||
|
cwd='/home/moltbot/clawd',
|
||||||
|
capture_output=True,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
assert result.returncode == 0, f"Typecheck failed: {result.stderr}"
|
||||||
|
print("✓ Test 170 passed: Typecheck successful")
|
||||||
|
|||||||
Reference in New Issue
Block a user