Skip to content

Instantly share code, notes, and snippets.

@mottzi
Last active July 11, 2025 00:17
Show Gist options
  • Save mottzi/2bb354ad781fe47e6e76a71211b2bc33 to your computer and use it in GitHub Desktop.
Save mottzi/2bb354ad781fe47e6e76a71211b2bc33 to your computer and use it in GitHub Desktop.
import SwiftUI
extension HabitCard {
var barChart: some View {
Capsule()
.fill(.quaternary)
.overlay {
GeometryReader { geometry in
let height = geometry.size.height
Capsule()
.fill(habit.color.gradient)
.background { targetBounceFiller(for: height) }
.offset(y: targetOffset(for: height))
.shadow(color: .black.opacity(0.07), radius: 2, x: 0, y: -2)
.background { overflowFiller(for: height)}
.clipShape(.capsule)
.padding(3)
.shadow(color: glowColor, radius: 4, x: 0, y: 6)
.animation(.bouncy(extraBounce: 0.1), value: progress)
}
}
.frame(width: barChartWidth)
}
}
extension HabitCard {
func targetOffset(for height: CGFloat) -> CGFloat {
switch progress {
case ...0: height
case 0..<1: height * (1 - progress) - 12
case 1: 0
case 1...: height * (1 - (1 / progress)) - 12
default : height
}
}
func overflowOffset(for height: CGFloat) -> CGFloat {
progress > 1 ? 0 : targetOffset(for: height) + barChartWidth / 2
}
var glowColor: Color {
switch colorScheme {
case .light: habit.color.opacity(0.1)
case .dark: habit.color.opacity(0.05)
@unknown default: habit.color.opacity(0.1)
}
}
}
extension HabitCard {
func targetBounceFiller(for height: CGFloat) -> some View {
Rectangle()
.fill(habit.color.gradient)
.frame(height: height / 2 + barChartWidth / 2)
.frame(maxHeight: .infinity, alignment: .bottom)
.offset(y: barChartWidth / 2)
}
func overflowFiller(for height: CGFloat) -> some View {
Capsule()
.fill(habit.color.gradient)
.brightness(-0.035)
.rotationEffect(.degrees(180))
.offset(y: overflowOffset(for: height))
.animation(.bouncy(duration: 0.85, extraBounce: 0.2), value: progress)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment