Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:48:55 +08:00
commit f28999f19c
127 changed files with 62038 additions and 0 deletions

View File

@@ -0,0 +1,393 @@
#!/bin/bash
# Apple HIG Designer - Design Validation
# Validate Swift code against Apple Human Interface Guidelines
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
NC='\033[0m' # No Color
# Counters
PASS_COUNT=0
FAIL_COUNT=0
WARNING_COUNT=0
# Helper functions
print_success() {
echo -e "${GREEN}✓ PASS${NC} $1"
((PASS_COUNT++))
}
print_error() {
echo -e "${RED}✗ FAIL${NC} $1"
((FAIL_COUNT++))
}
print_warning() {
echo -e "${YELLOW}⚠ WARN${NC} $1"
((WARNING_COUNT++))
}
print_info() {
echo -e "${BLUE} INFO${NC} $1"
}
print_section() {
echo ""
echo -e "${MAGENTA}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${MAGENTA}$1${NC}"
echo -e "${MAGENTA}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
}
# Banner
echo ""
echo "╔════════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ Apple HIG Designer - Design Validation ║"
echo "║ ║"
echo "╚════════════════════════════════════════════════════════════╝"
echo ""
# Get target
if [ -z "$1" ]; then
print_info "Usage: $0 <file.swift|directory>"
print_info "Example: $0 ContentView.swift"
print_info "Example: $0 Views/"
exit 1
fi
TARGET="$1"
# Check if target exists
if [ ! -e "$TARGET" ]; then
print_error "Target not found: $TARGET"
exit 1
fi
# Section 1: Typography
print_section "1. TYPOGRAPHY"
check_system_fonts() {
# Check for system font usage
if grep -q '\.font(' "$1"; then
if grep -q '\.font(.body)\|\.font(.title)\|\.font(.headline)' "$1"; then
print_success "Using system text styles (Dynamic Type)"
else
print_warning "Consider using system text styles (.body, .headline, etc.)"
fi
fi
# Check for hard-coded font sizes
if grep -q 'Font.system(size:' "$1"; then
print_warning "Hard-coded font sizes found - consider Dynamic Type"
echo " Tip: Use .font(.body) instead of .font(.system(size: 17))"
fi
}
# Section 2: Colors
print_section "2. COLORS & DARK MODE"
check_semantic_colors() {
# Check for semantic color usage
if grep -q 'Color(.label)\|Color(.systemBackground)\|Color(.secondary)' "$1"; then
print_success "Using semantic colors (dark mode support)"
else
if grep -q 'Color(' "$1"; then
print_warning "Consider using semantic colors for dark mode support"
echo " Use: Color(.label) instead of Color.black"
fi
fi
# Check for hard-coded colors
if grep -q '#[0-9A-Fa-f]\{6\}\|Color.black\|Color.white' "$1"; then
print_error "Hard-coded colors found - use semantic colors"
echo " Fix: Use Color(.label), Color(.systemBackground), etc."
fi
}
# Section 3: Accessibility
print_section "3. ACCESSIBILITY"
check_accessibility_labels() {
# Check for accessibility labels
if grep -q 'Image(systemName:' "$1"; then
if grep -q '\.accessibilityLabel' "$1"; then
print_success "SF Symbols have accessibility labels"
else
print_error "SF Symbols missing accessibility labels"
echo " Fix: Add .accessibilityLabel(\"Description\")"
fi
fi
# Check for VoiceOver support
if grep -q '\.accessibilityLabel\|\.accessibilityHint\|\.accessibilityValue' "$1"; then
print_success "VoiceOver support implemented"
else
print_warning "Consider adding VoiceOver support"
fi
}
# Section 4: Touch Targets
print_section "4. TOUCH TARGETS"
check_touch_targets() {
# Check for minimum tap targets
if grep -q '\.frame(.*height.*44\|minHeight.*44' "$1"; then
print_success "Minimum touch target size (44pt) specified"
else
if grep -q 'Button\|.onTapGesture' "$1"; then
print_warning "Verify touch targets are at least 44x44 points"
echo " Tip: .frame(minWidth: 44, minHeight: 44)"
fi
fi
}
# Section 5: Spacing
print_section "5. SPACING & LAYOUT"
check_spacing() {
# Check for 8pt grid usage
if grep -q '\.padding([0-9]*)\|\.spacing([0-9]*)' "$1"; then
# Extract padding values
paddings=$(grep -o '\.padding([0-9]*)' "$1" | grep -o '[0-9]*')
invalid=false
for pad in $paddings; do
if [ $((pad % 8)) -ne 0 ]; then
invalid=true
break
fi
done
if [ "$invalid" = false ]; then
print_success "Following 8pt grid system"
else
print_warning "Consider using 8pt grid (8, 16, 24, 32, etc.)"
fi
fi
# Check for safe area usage
if grep -q '\.ignoresSafeArea' "$1"; then
print_warning "Ignoring safe areas - ensure intentional"
echo " Tip: Respect safe areas for better device compatibility"
fi
}
# Section 6: Navigation
print_section "6. NAVIGATION"
check_navigation() {
# Check for navigation best practices
if grep -q 'NavigationStack\|NavigationView' "$1"; then
if grep -q '\.navigationTitle' "$1"; then
print_success "Navigation titles present"
else
print_error "NavigationStack missing .navigationTitle"
fi
# Check for navigation bar mode
if grep -q '\.navigationBarTitleDisplayMode(.large)' "$1"; then
print_success "Using large titles for top-level views"
fi
fi
# Check for TabView
if grep -q 'TabView' "$1"; then
# Count tabItems
tab_count=$(grep -c '\.tabItem' "$1")
if [ "$tab_count" -ge 3 ] && [ "$tab_count" -le 5 ]; then
print_success "TabView has appropriate number of tabs ($tab_count)"
elif [ "$tab_count" -gt 5 ]; then
print_error "Too many tabs ($tab_count) - maximum 5 recommended"
elif [ "$tab_count" -lt 3 ]; then
print_warning "Consider if TabView is appropriate for $tab_count tabs"
fi
fi
}
# Section 7: Buttons
print_section "7. BUTTONS & CONTROLS"
check_buttons() {
# Check for button styles
if grep -q 'Button(' "$1"; then
if grep -q '\.buttonStyle' "$1"; then
print_success "Using button styles"
# Check for button hierarchy
if grep -q '\.buttonStyle(.borderedProminent)' "$1"; then
prominent_count=$(grep -c '\.buttonStyle(.borderedProminent)' "$1")
if [ "$prominent_count" -eq 1 ]; then
print_success "Single prominent button (good hierarchy)"
else
print_warning "Multiple prominent buttons - ensure clear hierarchy"
fi
fi
else
print_warning "Consider using .buttonStyle for consistent appearance"
fi
# Check button labels
if grep -q 'Button("' "$1"; then
# Extract button texts
if grep -q 'Button("[A-Z]' "$1"; then
print_success "Button labels start with capital letters"
fi
fi
fi
}
# Section 8: Lists
print_section "8. LISTS & TABLES"
check_lists() {
# Check for list styles
if grep -q 'List' "$1"; then
if grep -q '\.listStyle' "$1"; then
if grep -q '\.listStyle(.insetGrouped)' "$1"; then
print_success "Using iOS standard .insetGrouped list style"
fi
else
print_warning "Consider specifying .listStyle(.insetGrouped)"
fi
fi
}
# Section 9: Animations
print_section "9. ANIMATIONS & MOTION"
check_animations() {
# Check for spring animations
if grep -q 'withAnimation' "$1"; then
if grep -q '\.spring()\|\.easeInOut' "$1"; then
print_success "Using iOS-style animations"
fi
fi
# Check for reduce motion
if grep -q '@Environment(.*accessibilityReduceMotion)' "$1"; then
print_success "Respecting Reduce Motion preference"
else
if grep -q 'withAnimation\|\.animation' "$1"; then
print_warning "Consider respecting Reduce Motion accessibility setting"
echo " Tip: @Environment(\\.accessibilityReduceMotion) var reduceMotion"
fi
fi
}
# Section 10: SF Symbols
print_section "10. SF SYMBOLS"
check_sf_symbols() {
# Check for SF Symbols usage
if grep -q 'Image(systemName:' "$1"; then
print_success "Using SF Symbols"
# Check for proper sizing
if grep -q '\.font(.title)\|\.imageScale' "$1"; then
print_success "SF Symbols are properly sized"
else
print_warning "Consider sizing SF Symbols with .font() or .imageScale()"
fi
fi
# Check for custom images that should be SF Symbols
common_icons="heart|star|person|home|settings|search|share"
if grep -E "Image\\(\"($common_icons)" "$1"; then
print_warning "Consider using SF Symbols instead of custom icons"
fi
}
# Run checks on files
if [ -f "$TARGET" ]; then
# Single file
if [[ "$TARGET" == *.swift ]]; then
check_system_fonts "$TARGET"
check_semantic_colors "$TARGET"
check_accessibility_labels "$TARGET"
check_touch_targets "$TARGET"
check_spacing "$TARGET"
check_navigation "$TARGET"
check_buttons "$TARGET"
check_lists "$TARGET"
check_animations "$TARGET"
check_sf_symbols "$TARGET"
else
print_error "File is not a Swift file: $TARGET"
exit 1
fi
elif [ -d "$TARGET" ]; then
# Directory - find Swift files
swift_files=$(find "$TARGET" -name "*.swift" 2>/dev/null)
if [ -z "$swift_files" ]; then
print_error "No Swift files found in $TARGET"
exit 1
fi
for file in $swift_files; do
print_info "Checking: $file"
check_system_fonts "$file"
check_semantic_colors "$file"
check_accessibility_labels "$file"
check_touch_targets "$file"
check_spacing "$file"
echo ""
done
fi
# Summary
echo ""
echo "╔════════════════════════════════════════════════════════════╗"
echo "║ Validation Summary ║"
echo "╚════════════════════════════════════════════════════════════╝"
echo ""
echo -e "${GREEN}✓ Passed: $PASS_COUNT${NC}"
echo -e "${RED}✗ Failed: $FAIL_COUNT${NC}"
echo -e "${YELLOW}⚠ Warnings: $WARNING_COUNT${NC}"
echo ""
# Calculate score
TOTAL=$((PASS_COUNT + FAIL_COUNT))
if [ $TOTAL -gt 0 ]; then
SCORE=$(( (PASS_COUNT * 100) / TOTAL ))
echo "HIG Compliance Score: $SCORE%"
echo ""
if [ $SCORE -ge 90 ]; then
echo -e "${GREEN}Excellent! Your design follows Apple HIG.${NC}"
elif [ $SCORE -ge 70 ]; then
echo -e "${YELLOW}Good, but needs improvements.${NC}"
else
echo -e "${RED}Needs significant improvements to match Apple HIG.${NC}"
fi
fi
echo ""
print_info "Apple HIG Recommendations:"
echo " 1. Use system fonts with Dynamic Type"
echo " 2. Use semantic colors for dark mode"
echo " 3. Add VoiceOver labels to all images"
echo " 4. Ensure 44x44pt minimum touch targets"
echo " 5. Follow 8pt grid system"
echo " 6. Use large titles for top-level navigation"
echo " 7. Limit TabView to 3-5 tabs"
echo " 8. Use .borderedProminent for primary actions only"
echo ""
print_info "Resources:"
echo " - Apple HIG: https://developer.apple.com/design/human-interface-guidelines/"
echo " - SF Symbols: https://developer.apple.com/sf-symbols/"
echo " - WWDC Videos: https://developer.apple.com/videos/"
echo ""
# Exit code based on failures
if [ $FAIL_COUNT -gt 0 ]; then
exit 1
else
exit 0
fi