Created
January 23, 2023 12:17
-
-
Save mortenjust/a8bcbd481b8379ec46ca8c640c33db9b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// DarkModeMasker.swift | |
// SwiftUI Demos | |
// | |
// Created by Morten Just on 1/22/23. | |
// https://twitter.com/joshguospace/status/1617101052192649216?s=12 | |
import SwiftUI | |
import Charts | |
struct DarkModeMasker: View { | |
@State var name = "" | |
@State var sales = [Int]() | |
@State var dates = [Int]() | |
@State var isLight = false | |
func DataPoint(_ data: String, label: String) -> some View { | |
VStack { | |
Text(data).font(.largeTitle).opacity(0.9) | |
Text(label).font(.caption).opacity(0.5) | |
} | |
} | |
func ModeToggle() -> some View { | |
HStack { | |
Spacer() | |
Toggle(isOn: $isLight) { | |
Text("Light") | |
} | |
.toggleStyle(.switch) | |
.padding() | |
} | |
} | |
func MainView(_ isDark : Bool) -> some View { | |
VStack { | |
ModeToggle() | |
VStack { | |
let chartStroke = isDark ? Color.yellow : Color.blue | |
let chartFill = LinearGradient( | |
colors: [chartStroke.opacity(0.5), .clear], | |
startPoint: .top, | |
endPoint: .bottom) | |
let dateWindow = dates.suffix(30) | |
let salesWindow = sales.suffix(30) | |
Text("Sales").font(.largeTitle.bold()) | |
.frame(maxWidth: .infinity, alignment: .leading) | |
Chart { | |
ForEach(dateWindow, id: \.self) { | |
// fill | |
AreaMark(x: .value("Date", $0), y: .value("Sales", sales[$0])) | |
.foregroundStyle(chartFill) | |
// .interpolationMethod(.catmullRom) | |
// line/border | |
LineMark(x: .value("Date", $0), y: .value("Sales", sales[$0])) | |
.foregroundStyle(chartStroke) | |
// .interpolationMethod(.catmullRom) | |
} | |
if !dates.isEmpty { | |
// average | |
RuleMark(y: .value("Average", (sales.reduce(0, +) / sales.count) )) | |
.lineStyle(.init(lineWidth: 0.5)) | |
.foregroundStyle( | |
isDark ? Color.orange : Color.purple | |
) | |
// dot | |
PointMark(x: .value("Today", dates[8]), y: .value("Sales", sales[8])) | |
.foregroundStyle( | |
isDark | |
? Color.white.shadow(.drop(color: .white, radius: 2)) | |
: Color.black.shadow(.drop(radius: 0)) | |
) | |
} | |
} | |
.chartXScale(domain: (dateWindow.first ?? 0)...(dateWindow.last ?? 0)) | |
HStack(spacing: 35) { | |
DataPoint("$393", label: "Avg.") | |
DataPoint("$29", label: "Per min") | |
DataPoint("$529", label: "Max") | |
}.padding(.top) | |
} | |
.padding(30) | |
.background { Color.primary.opacity(0.04)} | |
.cornerRadius(10) | |
.padding(30) | |
} | |
.frame(maxWidth: .infinity, maxHeight: .infinity) | |
.background { | |
Rectangle().fill(Color(nsColor: isDark ? .black : .windowBackgroundColor)) | |
} | |
.colorScheme(isDark ? .dark : .light) | |
} | |
@State var sliderX : CGFloat = 0 | |
var body: some View { | |
ZStack { | |
GeometryReader { reader in | |
let w = reader.size.width | |
MainView(true) | |
MainView(false) | |
.mask { | |
ZStack { | |
HStack { // draggable mask | |
Rectangle() | |
.frame(width: sliderX) | |
Spacer() | |
} | |
Circle() // circle mask | |
.position(x: w, y:0) | |
.scaleEffect(isLight ? 4 : 0, anchor: .topTrailing) | |
} | |
} | |
VStack { | |
Spacer() | |
// slider | |
Capsule() | |
.position(x: sliderX) | |
.frame(width: 15, height: 10) | |
.simultaneousGesture(DragGesture() | |
.onChanged({ value in | |
sliderX = min(max(value.location.x, 0), w) | |
}) | |
) | |
Spacer() | |
} | |
} | |
} | |
.animation(.default, value: isLight) | |
.ignoresSafeArea() | |
.onTapGesture { // click anywhere to toggle | |
isLight.toggle() | |
} | |
// initial dummy data | |
.onAppear { | |
sales = (0...32).map { Int.random(in: 10...50) + $0 * 2 } | |
dates = (0...30).map { $0 } | |
} // streaming dummy data | |
.onReceive(Timer.publish(every: 0.67, on: .main, in: .default).autoconnect(), perform: { _ in | |
sales.append(Int.random(in: 10...50) + sales.count) | |
dates.append(dates.last! + 1) | |
}) | |
} | |
} | |
struct DarkModeMasker_Previews: PreviewProvider { | |
static var previews: some View { | |
DarkModeMasker() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment