Improve pattern theme with visible mood icon backgrounds
- Remove pattern from month section header for cleaner look - Fix entry rows to show mood icon as repeating background - Add ultraThinMaterial behind text for better readability 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -574,50 +574,19 @@ extension DayView {
|
||||
}
|
||||
|
||||
private func patternSectionHeader(month: Int, year: Int) -> some View {
|
||||
ZStack {
|
||||
// Subtle mood icon pattern background
|
||||
GeometryReader { geo in
|
||||
let iconSize: CGFloat = 12
|
||||
let spacing: CGFloat = 20
|
||||
let cols = Int(geo.size.width / spacing) + 1
|
||||
let rows = 3
|
||||
HStack(spacing: 10) {
|
||||
Image(systemName: "calendar")
|
||||
.font(.system(size: 16, weight: .semibold))
|
||||
.foregroundColor(textColor.opacity(0.6))
|
||||
|
||||
Canvas { context, size in
|
||||
for row in 0..<rows {
|
||||
for col in 0..<cols {
|
||||
let x = CGFloat(col) * spacing + (row % 2 == 0 ? 0 : spacing / 2)
|
||||
let y = CGFloat(row) * spacing + 8
|
||||
let rect = CGRect(x: x, y: y, width: iconSize, height: iconSize)
|
||||
context.opacity = 0.06
|
||||
context.fill(Circle().path(in: rect), with: .color(textColor))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(height: 60)
|
||||
Text("\(Random.monthName(fromMonthInt: month)) \(String(year))")
|
||||
.font(.system(size: 20, weight: .bold, design: .rounded))
|
||||
.foregroundColor(textColor)
|
||||
|
||||
HStack(spacing: 12) {
|
||||
// Mood icon cluster
|
||||
HStack(spacing: -4) {
|
||||
ForEach(0..<3, id: \.self) { i in
|
||||
Circle()
|
||||
.fill(textColor.opacity(0.15 - Double(i) * 0.04))
|
||||
.frame(width: 20 - CGFloat(i * 2), height: 20 - CGFloat(i * 2))
|
||||
}
|
||||
}
|
||||
|
||||
Text(Random.monthName(fromMonthInt: month))
|
||||
.font(.system(size: 18, weight: .semibold))
|
||||
.foregroundColor(textColor)
|
||||
|
||||
Text(String(year))
|
||||
.font(.system(size: 14, weight: .regular))
|
||||
.foregroundColor(textColor.opacity(0.5))
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 14)
|
||||
.background(.ultraThinMaterial)
|
||||
}
|
||||
|
||||
|
||||
@@ -1274,84 +1274,84 @@ struct EntryListView: View {
|
||||
|
||||
// MARK: - Pattern Style (Mood icons as repeating background)
|
||||
private var patternStyle: some View {
|
||||
ZStack {
|
||||
HStack(spacing: 16) {
|
||||
// Large mood icon
|
||||
ZStack {
|
||||
Circle()
|
||||
.fill(isMissing ? Color.gray.opacity(0.2) : moodColor)
|
||||
.frame(width: 54, height: 54)
|
||||
|
||||
imagePack.icon(forMood: entry.mood)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 28, height: 28)
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(entry.forDate, format: .dateTime.weekday(.wide).day())
|
||||
.font(.system(size: 17, weight: .semibold))
|
||||
.foregroundColor(textColor)
|
||||
|
||||
if isMissing {
|
||||
Text("No mood recorded")
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(.gray)
|
||||
} else {
|
||||
Text(entry.moodString)
|
||||
.font(.system(size: 15, weight: .medium))
|
||||
.foregroundColor(moodColor)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 8)
|
||||
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 10))
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(entry.forDate, format: .dateTime.month(.abbreviated))
|
||||
.font(.system(size: 12, weight: .medium))
|
||||
.foregroundColor(textColor.opacity(0.6))
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical, 6)
|
||||
.background(.ultraThinMaterial, in: Capsule())
|
||||
}
|
||||
.padding(16)
|
||||
.frame(height: 86)
|
||||
.background {
|
||||
// Repeating mood icon pattern background
|
||||
GeometryReader { geo in
|
||||
let iconSize: CGFloat = 24
|
||||
let spacing: CGFloat = 32
|
||||
let iconSize: CGFloat = 20
|
||||
let spacing: CGFloat = 28
|
||||
let cols = Int(geo.size.width / spacing) + 2
|
||||
let rows = Int(geo.size.height / spacing) + 2
|
||||
|
||||
ForEach(0..<rows, id: \.self) { row in
|
||||
ForEach(0..<cols, id: \.self) { col in
|
||||
imagePack.icon(forMood: entry.mood)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: iconSize, height: iconSize)
|
||||
.foregroundColor(isMissing ? Color.gray.opacity(0.08) : moodColor.opacity(0.12))
|
||||
.position(
|
||||
x: CGFloat(col) * spacing + (row.isMultiple(of: 2) ? spacing/2 : 0),
|
||||
y: CGFloat(row) * spacing
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.clipped()
|
||||
|
||||
// Content card
|
||||
HStack(spacing: 16) {
|
||||
// Large mood icon
|
||||
ZStack {
|
||||
Circle()
|
||||
.fill(isMissing ? Color.gray.opacity(0.2) : moodColor)
|
||||
.frame(width: 54, height: 54)
|
||||
// Base background color
|
||||
RoundedRectangle(cornerRadius: 16)
|
||||
.fill(colorScheme == .dark ? Color(.systemGray6) : Color(.systemGray6).opacity(0.5))
|
||||
|
||||
imagePack.icon(forMood: entry.mood)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 28, height: 28)
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(entry.forDate, format: .dateTime.weekday(.wide).day())
|
||||
.font(.system(size: 17, weight: .semibold))
|
||||
.foregroundColor(textColor)
|
||||
|
||||
if isMissing {
|
||||
Text("No mood recorded")
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(.gray)
|
||||
} else {
|
||||
Text(entry.moodString)
|
||||
.font(.system(size: 15, weight: .medium))
|
||||
.foregroundColor(moodColor)
|
||||
// Pattern overlay
|
||||
ForEach(0..<rows, id: \.self) { row in
|
||||
ForEach(0..<cols, id: \.self) { col in
|
||||
imagePack.icon(forMood: entry.mood)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: iconSize, height: iconSize)
|
||||
.foregroundColor(isMissing ? Color.gray.opacity(0.15) : moodColor.opacity(0.2))
|
||||
.position(
|
||||
x: CGFloat(col) * spacing + (row.isMultiple(of: 2) ? spacing/2 : 0),
|
||||
y: CGFloat(row) * spacing
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(entry.forDate, format: .dateTime.month(.abbreviated))
|
||||
.font(.system(size: 12, weight: .medium))
|
||||
.foregroundColor(textColor.opacity(0.4))
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical, 6)
|
||||
.background(
|
||||
Capsule()
|
||||
.fill(textColor.opacity(0.08))
|
||||
)
|
||||
}
|
||||
.padding(16)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 16)
|
||||
.fill(colorScheme == .dark ? Color(.systemGray6).opacity(0.95) : Color.white.opacity(0.95))
|
||||
)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 16))
|
||||
}
|
||||
.frame(height: 86)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 16))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 16)
|
||||
.stroke(isMissing ? Color.gray.opacity(0.15) : moodColor.opacity(0.25), lineWidth: 1)
|
||||
.stroke(isMissing ? Color.gray.opacity(0.15) : moodColor.opacity(0.3), lineWidth: 1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user