Skip to content

Instantly share code, notes, and snippets.

@mobibob
Last active September 13, 2024 22:02
Show Gist options
  • Save mobibob/80ae91e66b53384829ef3bf5b54586b4 to your computer and use it in GitHub Desktop.
Save mobibob/80ae91e66b53384829ef3bf5b54586b4 to your computer and use it in GitHub Desktop.
SwiftUI Color Extension - contrasting for text on background
extension Color {
static var forExampleMyDarkRed: Color {
return Color(hue: 1.0, saturation: 1.0, brightness: 0.6, opacity: 0.8)
}
init(hex: String) {
let scanner = Scanner(string: hex)
_ = scanner.scanString("#") // Skip the '#' prefix if present
var rgb: UInt64 = 0
scanner.scanHexInt64(&rgb)
let r = Double((rgb & 0xFF0000) >> 16) / 255.0
let g = Double((rgb & 0x00FF00) >> 8) / 255.0
let b = Double(rgb & 0x0000FF) / 255.0
self.init(red: r, green: g, blue: b, opacity: 1.0)
}
func toHex2() -> String {
return self.description
}
func isLight() -> Bool {
let components = self.cgColor?.components
let h = (components?[0] ?? 0) * 299
let v = (components?[1] ?? 0) * 587
let b = components?[2] ?? 0
let brightness = (h + v + (b) * 114) / 1000
return brightness > 0.5
}
func contrastingColor() -> Color {
return self.isLight() ? .black : .white
}
static let customPurple = Color(red: 128/255, green: 0/255, blue: 128/255)
static let customTeal = Color(red: 0/255, green: 128/255, blue: 128/255)
static var tone0: Color { Color(hex: "000000") }
static var tone10: Color { Color(hex: "1A1A1A") }
static var tone20: Color { Color(hex: "333333") }
static var tone30: Color { Color(hex: "4D4D4D") }
static var tone40: Color { Color(hex: "676767") }
static var tone50: Color { Color(hex: "808080") }
static var tone60: Color { Color(hex: "999999") }
static var tone70: Color { Color(hex: "B3B3B3") }
static var tone80: Color { Color(hex: "CCCCCC") }
static var tone90: Color { Color(hex: "E6E6E6") }
static var tone95: Color { Color(hex: "F2F2F2") }
static var tone99: Color { Color(hex: "FAFAFA") }
static var tone100: Color { Color(hex: "FFFFFF") }
}
import SwiftUI
struct TonalPalette: Identifiable {
let id = UUID()
let name: String
let colors: [TonalColor]
}
// make this conform to hashable
final class TonalColor: Hashable {
var id: UUID
var tonalColor: Color
init(id: UUID = UUID() ,tonalColor: Color) {
self.id = id
self.tonalColor = tonalColor
}
static func == (lhs: TonalColor, rhs: TonalColor) -> Bool {
lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
// MARK: - ViewModel
class PaletteChoices: ObservableObject {
static let shared = PaletteChoices()
@Published var palettes: [TonalPalette] = []
private init() {
loadPalettes()
}
private func loadPalettes() {
palettes = [
TonalPalette(name: "Purple", colors: [
TonalColor(tonalColor: Color.tone0),
TonalColor(tonalColor: Color.tone10),
TonalColor(tonalColor: Color.tone20),
TonalColor(tonalColor: Color.tone30),
TonalColor(tonalColor: Color.tone40),
TonalColor(tonalColor: .yellow.opacity(0.5)),
TonalColor(tonalColor: Color.tone50),
TonalColor(tonalColor: Color.tone60),
TonalColor(tonalColor: Color.tone70.opacity(0.9)),
TonalColor(tonalColor: Color.tone80),
TonalColor(tonalColor: .purple.opacity(0.5)),
TonalColor(tonalColor: Color.tone95),
TonalColor(tonalColor: Color.tone99),
TonalColor(tonalColor: Color.tone100),
]),
TonalPalette(name: "Teal", colors: [
TonalColor(tonalColor: .teal.opacity(0.1)),
TonalColor(tonalColor: Color.tone10),
TonalColor(tonalColor: .teal.opacity(0.2)),
TonalColor(tonalColor: .teal.opacity(0.3)),
TonalColor(tonalColor: .teal.opacity(0.4)),
TonalColor(tonalColor: .teal.opacity(0.5)),
TonalColor(tonalColor: .teal.opacity(0.6)),
TonalColor(tonalColor: .teal.opacity(0.7)),
TonalColor(tonalColor: .teal.opacity(0.8)),
TonalColor(tonalColor: .teal.opacity(0.9)),
TonalColor(tonalColor: .teal)
]),
// Add more palettes here...
]
}
}
#Preview("Palette") {
VStack() {
HStack(alignment: .center) {
ContentView()
.frame(width: 320, height: 280)
}
}
}
struct ContentView: View {
@StateObject private var paletteChoices = PaletteChoices.shared
var body: some View {
List {
ForEach(paletteChoices.palettes) { palette in
Section(header: Text(palette.name)
.foregroundColor(Color.accentColor)
.font(.title2)) {
ForEach(palette.colors, id: \.self) { color in
Text("\(color.tonalColor.toHex2())")
.font(.caption)
.containerShape(Rectangle())
.frame(width: 90, height: 30)
.background(color.tonalColor)
.foregroundColor(color.tonalColor.contrastingColor())
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment