Add dynamic text contrast for mood colors and make theme preview full screen
- Add WCAG-compliant luminance calculation to Color extension - Add contrastingTextColor method to MoodTints for automatic black/white text - Update 12+ entry styles to use dynamic text colors instead of hardcoded white - Change theme preview sheet to full screen presentation Text now automatically switches between black and white based on background brightness, fixing readability issues on light mood colors like yellow (Good). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,11 @@ struct EntryListView: View {
|
||||
moodTint.color(forMood: entry.mood)
|
||||
}
|
||||
|
||||
/// Text color that contrasts with the mood's background color
|
||||
private var moodContrastingTextColor: Color {
|
||||
moodTint.contrastingTextColor(forMood: entry.mood)
|
||||
}
|
||||
|
||||
private var isMissing: Bool {
|
||||
entry.moodValue == Mood.missing.rawValue
|
||||
}
|
||||
@@ -109,7 +114,7 @@ struct EntryListView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 32, height: 32)
|
||||
.foregroundColor(isMissing ? .gray : .white)
|
||||
.foregroundColor(isMissing ? .gray : moodContrastingTextColor)
|
||||
.accessibilityLabel(entry.mood.strValue)
|
||||
}
|
||||
.shadow(color: isMissing ? .clear : moodColor.opacity(0.4), radius: 8, x: 0, y: 4)
|
||||
@@ -284,13 +289,13 @@ struct EntryListView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 28, height: 28)
|
||||
.foregroundColor(isMissing ? .gray : .white)
|
||||
.foregroundColor(isMissing ? .gray : moodContrastingTextColor)
|
||||
.accessibilityLabel(entry.mood.strValue)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(entry.forDate, format: .dateTime.weekday(.wide).day())
|
||||
.font(.subheadline.weight(.semibold))
|
||||
.foregroundColor(isMissing ? textColor : .white)
|
||||
.foregroundColor(isMissing ? textColor : moodContrastingTextColor)
|
||||
|
||||
if isMissing {
|
||||
Text(String(localized: "mood_value_missing_tap_to_add"))
|
||||
@@ -299,7 +304,7 @@ struct EntryListView: View {
|
||||
} else {
|
||||
Text(entry.moodString)
|
||||
.font(.caption.weight(.medium))
|
||||
.foregroundColor(.white.opacity(0.85))
|
||||
.foregroundColor(moodContrastingTextColor.opacity(0.85))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,7 +312,7 @@ struct EntryListView: View {
|
||||
|
||||
Image(systemName: "chevron.right")
|
||||
.font(.caption.weight(.semibold))
|
||||
.foregroundColor(isMissing ? textColor.opacity(0.3) : .white.opacity(0.6))
|
||||
.foregroundColor(isMissing ? textColor.opacity(0.3) : moodContrastingTextColor.opacity(0.6))
|
||||
}
|
||||
.padding(.horizontal, 18)
|
||||
.padding(.vertical, 14)
|
||||
@@ -345,7 +350,7 @@ struct EntryListView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.padding(16)
|
||||
.foregroundColor(isMissing ? .gray : .white)
|
||||
.foregroundColor(isMissing ? .gray : moodContrastingTextColor)
|
||||
.accessibilityLabel(entry.mood.strValue)
|
||||
}
|
||||
.shadow(
|
||||
@@ -429,7 +434,7 @@ struct EntryListView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 20, height: 20)
|
||||
.foregroundColor(isMissing ? .gray : .white)
|
||||
.foregroundColor(isMissing ? .gray : moodContrastingTextColor)
|
||||
.accessibilityLabel(entry.mood.strValue)
|
||||
}
|
||||
|
||||
@@ -974,7 +979,7 @@ struct EntryListView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 26, height: 26)
|
||||
.foregroundColor(isMissing ? .gray : .white)
|
||||
.foregroundColor(isMissing ? .gray : moodContrastingTextColor)
|
||||
.accessibilityLabel(entry.mood.strValue)
|
||||
}
|
||||
|
||||
@@ -1182,7 +1187,7 @@ struct EntryListView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 24, height: 24)
|
||||
.foregroundColor(.white)
|
||||
.foregroundColor(moodContrastingTextColor)
|
||||
.accessibilityLabel(entry.mood.strValue)
|
||||
}
|
||||
|
||||
@@ -1379,7 +1384,7 @@ struct EntryListView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 28, height: 28)
|
||||
.foregroundColor(isMissing ? .gray : .white)
|
||||
.foregroundColor(isMissing ? .gray : moodContrastingTextColor)
|
||||
.accessibilityLabel(entry.mood.strValue)
|
||||
.padding(.leading, 16)
|
||||
|
||||
@@ -1390,7 +1395,7 @@ struct EntryListView: View {
|
||||
} else {
|
||||
Text(entry.moodString)
|
||||
.font(.body.weight(.semibold))
|
||||
.foregroundColor(.white)
|
||||
.foregroundColor(moodContrastingTextColor)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
@@ -1398,7 +1403,7 @@ struct EntryListView: View {
|
||||
// Month indicator
|
||||
Text(entry.forDate, format: .dateTime.month(.abbreviated))
|
||||
.font(.caption2.weight(.bold))
|
||||
.foregroundColor(isMissing ? .gray : .white.opacity(0.7))
|
||||
.foregroundColor(isMissing ? .gray : moodContrastingTextColor.opacity(0.7))
|
||||
.padding(.trailing, 16)
|
||||
}
|
||||
}
|
||||
@@ -1426,7 +1431,7 @@ struct EntryListView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 28, height: 28)
|
||||
.foregroundColor(.white)
|
||||
.foregroundColor(isMissing ? .gray : moodContrastingTextColor)
|
||||
.accessibilityLabel(entry.mood.strValue)
|
||||
}
|
||||
|
||||
@@ -1585,7 +1590,7 @@ struct EntryListView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 22, height: 22)
|
||||
.foregroundColor(.white)
|
||||
.foregroundColor(isMissing ? .gray : moodContrastingTextColor)
|
||||
.shadow(color: Color.black.opacity(0.3), radius: 1, x: 0, y: 1)
|
||||
.accessibilityLabel(entry.mood.strValue)
|
||||
}
|
||||
@@ -1718,7 +1723,7 @@ struct EntryListView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 24, height: 24)
|
||||
.foregroundColor(isMissing ? .gray : .white)
|
||||
.foregroundColor(isMissing ? .gray : moodContrastingTextColor)
|
||||
.accessibilityLabel(entry.mood.strValue)
|
||||
}
|
||||
|
||||
@@ -1946,7 +1951,7 @@ struct OrbitEntryView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 24, height: 24)
|
||||
.foregroundColor(.white)
|
||||
.foregroundColor(isMissing ? .gray : moodColor.contrastingTextColor)
|
||||
.accessibilityLabel(entry.mood.strValue)
|
||||
}
|
||||
|
||||
@@ -2130,7 +2135,7 @@ struct MotionCardView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 30, height: 30)
|
||||
.foregroundColor(.white)
|
||||
.foregroundColor(isMissing ? .gray : moodColor.contrastingTextColor)
|
||||
.offset(
|
||||
x: -motionManager.xOffset * 0.3,
|
||||
y: -motionManager.yOffset * 0.3
|
||||
|
||||
Reference in New Issue
Block a user