Skip to content

Instantly share code, notes, and snippets.

@Shriram-Vasudevan
Created April 16, 2025 21:15
Show Gist options
  • Save Shriram-Vasudevan/e9a20a79ff11da12daa18ecc5560ebf0 to your computer and use it in GitHub Desktop.
Save Shriram-Vasudevan/e9a20a79ff11da12daa18ecc5560ebf0 to your computer and use it in GitHub Desktop.
import SwiftUI
struct LightDarkMode: View {
@State private var isDarkMode: Bool = false
@State private var animationPhase: Double = 0
@State private var isPressed: Bool = false
let timer = Timer.publish(every: 0.05, on: .main, in: .common).autoconnect()
var body: some View {
ZStack {
backgroundColor
.ignoresSafeArea()
WaveView(
isDarkMode: isDarkMode,
animationPhase: animationPhase
)
.ignoresSafeArea()
HStack(spacing: 20) {
ZStack {
Circle()
.fill(
RadialGradient(
gradient: Gradient(colors: [
Color(red: 1.0, green: 0.9, blue: 0.6),
Color(red: 0.95, green: 0.8, blue: 0.5)
]),
center: .center,
startRadius: 1,
endRadius: 14
)
)
.frame(width: 28, height: 28)
.shadow(color: Color(red: 1.0, green: 0.8, blue: 0.4, opacity: 0.7), radius: 8)
.opacity(isDarkMode ? 0 : 1)
.scaleEffect(isDarkMode ? 0.01 : 1)
ZStack {
Circle()
.fill(
LinearGradient(
gradient: Gradient(colors: [
Color(red: 0.9, green: 0.9, blue: 1.0),
Color(red: 0.8, green: 0.8, blue: 0.9)
]),
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
.frame(width: 26, height: 26)
.shadow(color: Color(red: 0.5, green: 0.5, blue: 0.9, opacity: 0.3), radius: 8)
Circle()
.fill(
LinearGradient(
gradient: Gradient(colors: [
Color(red: 0.18, green: 0.18, blue: 0.25),
Color(red: 0.12, green: 0.12, blue: 0.18)
]),
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
.frame(width: 24, height: 24)
.offset(x: 4, y: -4)
}
.opacity(isDarkMode ? 1 : 0)
.scaleEffect(isDarkMode ? 1 : 0.01)
}
Text(isDarkMode ? "Dark Mode" : "Light Mode")
.font(.system(size: 17, weight: .medium, design: .rounded))
.foregroundColor(isDarkMode ?
Color(red: 0.95, green: 0.95, blue: 1.0) :
Color(red: 0.2, green: 0.2, blue: 0.3))
}
.padding(.horizontal, 24)
.padding(.vertical, 16)
.background(
Capsule()
.fill(
isDarkMode ?
LinearGradient(
gradient: Gradient(colors: [
Color(red: 0.18, green: 0.18, blue: 0.25),
Color(red: 0.12, green: 0.12, blue: 0.20)
]),
startPoint: .topLeading,
endPoint: .bottomTrailing
) :
LinearGradient(
gradient: Gradient(colors: [
Color.white,
Color(red: 0.95, green: 0.95, blue: 0.98)
]),
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
.shadow(
color: isDarkMode ?
Color.black.opacity(0.4) :
Color.black.opacity(0.12),
radius: 20,
x: 0,
y: 10
)
)
.overlay(
Capsule()
.strokeBorder(
LinearGradient(
gradient: Gradient(colors: [
isDarkMode ?
Color.white.opacity(0.2) :
Color.white.opacity(0.7),
isDarkMode ?
Color.white.opacity(0.05) :
Color.white.opacity(0.2)
]),
startPoint: .topLeading,
endPoint: .bottomTrailing
),
lineWidth: 1
)
)
.scaleEffect(isPressed ? 0.97 : 1)
.animation(.spring(response: 0.3, dampingFraction: 0.6), value: isPressed)
.onTapGesture {
withAnimation(.spring(response: 0.5, dampingFraction: 0.7)) {
isDarkMode.toggle()
let generator = UIImpactFeedbackGenerator(style: .medium)
generator.impactOccurred()
isPressed = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
isPressed = false
}
}
}
}
.onReceive(timer) { _ in
animationPhase += 0.05
if animationPhase > 100 {
animationPhase = 0
}
}
}
var backgroundColor: some View {
Group {
if isDarkMode {
LinearGradient(
gradient: Gradient(colors: [
Color(red: 0.08, green: 0.08, blue: 0.14),
Color(red: 0.12, green: 0.12, blue: 0.20)
]),
startPoint: .top,
endPoint: .bottom
)
} else {
LinearGradient(
gradient: Gradient(colors: [
Color(red: 0.98, green: 0.98, blue: 1.0),
Color(red: 0.95, green: 0.95, blue: 0.98)
]),
startPoint: .top,
endPoint: .bottom
)
}
}
.animation(.easeInOut(duration: 0.7), value: isDarkMode)
}
}
struct WaveView: View {
let isDarkMode: Bool
let animationPhase: Double
let waveCount = 4
var body: some View {
GeometryReader { geo in
ZStack {
ForEach(0..<waveCount, id: \.self) { index in
VisibleWaveLayer(
isDarkMode: isDarkMode,
index: index,
total: waveCount,
phase: animationPhase,
size: geo.size
)
}
}
}
.animation(.easeInOut(duration: 0.5), value: isDarkMode)
}
}
struct VisibleWaveLayer: View {
let isDarkMode: Bool
let index: Int
let total: Int
let phase: Double
let size: CGSize
var body: some View {
let layerPhase = phase + Double(index) * 0.3
let amplitude = size.height * 0.08
let waveDensity = 5.0 + Double(index) * 0.8
Path { path in
path.move(to: CGPoint(x: 0, y: size.height))
for x in stride(from: 0, to: size.width + 10, by: 4) {
let relativeX = Double(x) / Double(size.width)
let y1 = sin(relativeX * waveDensity + layerPhase)
let y2 = sin(relativeX * (waveDensity / 2) + layerPhase * 1.3)
let y = size.height * 0.7 + (y1 * 0.7 + y2 * 0.3) * amplitude
path.addLine(to: CGPoint(x: x, y: y))
}
path.addLine(to: CGPoint(x: size.width, y: size.height))
path.closeSubpath()
}
.fill(
LinearGradient(
gradient: Gradient(colors: waveColors),
startPoint: .top,
endPoint: .bottom
)
)
.opacity(waveOpacity)
.blur(radius: 12)
}
var waveColors: [Color] {
let intensity = Double(index) / Double(total - 1)
if isDarkMode {
return [
Color(red: 0.4, green: 0.4, blue: 0.9, opacity: 0.2 + intensity * 0.2),
Color(red: 0.2, green: 0.3, blue: 0.8, opacity: 0.1 + intensity * 0.2)
]
} else {
return [
Color(red: 0.3, green: 0.6, blue: 1.0, opacity: 0.2 + intensity * 0.15),
Color(red: 0.4, green: 0.7, blue: 1.0, opacity: 0.1 + intensity * 0.15)
]
}
}
var waveOpacity: Double {
let baseOpacity: Double = isDarkMode ? 0.7 : 0.5
return baseOpacity - Double(index) * 0.1
}
}
#Preview {
LightDarkMode()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment