SwiftUI
Use Turbo Themes in iOS and macOS applications with the Swift package.
SwiftUI Integration
Use Turbo Themes design tokens in iOS and macOS applications.
Installation
Swift Package Manager
Add Turbo Themes to your project via Xcode:
- Open your project in Xcode
- Go to File → Add Package Dependencies
- Enter the repository URL:
https://github.com/lgtm-hq/turbo-themes - Select the version and click Add Package
Or add it to your Package.swift:
dependencies: [
.package(url: "https://github.com/lgtm-hq/turbo-themes", from: "1.0.0")
]
Basic Usage
import SwiftUI
import TurboThemes
struct ContentView: View {
@StateObject private var themeManager = ThemeManager()
var body: some View {
VStack {
Text("Hello, Turbo Themes!")
.foregroundColor(themeManager.textPrimary)
Button("Primary Action") {
// action
}
.padding()
.background(themeManager.brandPrimary)
.foregroundColor(themeManager.textInverse)
.cornerRadius(8)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(themeManager.bgBase)
}
}
ThemeManager
Initialization
import TurboThemes
// Use default theme
let manager = ThemeManager()
// Use a specific theme
let manager = ThemeManager(themeId: .dracula)
Available Themes
enum ThemeId: String, CaseIterable {
case catppuccinMocha = "catppuccin-mocha"
case catppuccinMacchiato = "catppuccin-macchiato"
case catppuccinFrappe = "catppuccin-frappe"
case catppuccinLatte = "catppuccin-latte"
case dracula = "dracula"
case githubDark = "github-dark"
case githubLight = "github-light"
case bulmaDark = "bulma-dark"
case bulmaLight = "bulma-light"
}
Switching Themes
struct ThemeSwitcher: View {
@ObservedObject var themeManager: ThemeManager
var body: some View {
Picker("Theme", selection: $themeManager.currentTheme) {
ForEach(ThemeId.allCases, id: \.self) { theme in
Text(theme.displayName).tag(theme)
}
}
}
}
Color Properties
The ThemeManager provides all tokens as SwiftUI Color values:
Backgrounds
themeManager.bgBase // Main background
themeManager.bgSurface // Card/surface background
themeManager.bgOverlay // Overlay background
Text
themeManager.textPrimary // Main text color
themeManager.textSecondary // Muted text
themeManager.textInverse // Text on colored backgrounds
Brand
themeManager.brandPrimary // Primary accent color
State Colors
themeManager.stateSuccess // Success green
themeManager.stateWarning // Warning yellow
themeManager.stateDanger // Error red
themeManager.stateInfo // Info blue
Border
themeManager.borderDefault // Default border color
Building Components
Card Component
struct ThemedCard<Content: View>: View {
@EnvironmentObject var theme: ThemeManager
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
VStack(alignment: .leading) {
content
}
.padding()
.background(theme.bgSurface)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(theme.borderDefault, lineWidth: 1)
)
.cornerRadius(8)
}
}
// Usage
ThemedCard {
Text("Card Title")
.font(.headline)
.foregroundColor(theme.textPrimary)
Text("Card content goes here")
.foregroundColor(theme.textSecondary)
}
Button Styles
struct PrimaryButtonStyle: ButtonStyle {
@EnvironmentObject var theme: ThemeManager
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(theme.brandPrimary)
.foregroundColor(theme.textInverse)
.cornerRadius(6)
.opacity(configuration.isPressed ? 0.8 : 1.0)
}
}
struct DangerButtonStyle: ButtonStyle {
@EnvironmentObject var theme: ThemeManager
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(theme.stateDanger)
.foregroundColor(theme.textInverse)
.cornerRadius(6)
.opacity(configuration.isPressed ? 0.8 : 1.0)
}
}
// Usage
Button("Save") { }
.buttonStyle(PrimaryButtonStyle())
Button("Delete") { }
.buttonStyle(DangerButtonStyle())
Alert Component
struct ThemedAlert: View {
@EnvironmentObject var theme: ThemeManager
enum AlertType {
case success, warning, danger, info
}
let type: AlertType
let message: String
var backgroundColor: Color {
switch type {
case .success: return theme.stateSuccess
case .warning: return theme.stateWarning
case .danger: return theme.stateDanger
case .info: return theme.stateInfo
}
}
var body: some View {
Text(message)
.padding()
.frame(maxWidth: .infinity)
.background(backgroundColor)
.foregroundColor(theme.textInverse)
.cornerRadius(8)
}
}
Environment Object Setup
Set up the theme manager at the app level:
@main
struct MyApp: App {
@StateObject private var themeManager = ThemeManager()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(themeManager)
}
}
}
Then access it anywhere in your views:
struct MyView: View {
@EnvironmentObject var theme: ThemeManager
var body: some View {
Text("Themed text")
.foregroundColor(theme.textPrimary)
}
}
Persisting Theme Selection
class ThemeManager: ObservableObject {
@Published var currentTheme: ThemeId {
didSet {
UserDefaults.standard.set(currentTheme.rawValue, forKey: "turbo-theme")
}
}
init() {
if let saved = UserDefaults.standard.string(forKey: "turbo-theme"),
let theme = ThemeId(rawValue: saved) {
self.currentTheme = theme
} else {
self.currentTheme = .catppuccinMocha
}
}
}
Requirements
- iOS 15.0+
- macOS 12.0+
- Swift 5.9+
Next Steps
- Check the API Reference
- Learn about design tokens
- Explore other framework integrations