feat: added custom fonts cc233f3d
Steve · 2025-12-25 19:14 3 file(s) · +49 −8
Titan/Settings/ThemeSettings.swift +33 −0
6 6
import SwiftUI
7 7
import Combine
8 8
9 +
/// Available font design options for the browser
10 +
enum FontDesignOption: String, CaseIterable, Identifiable {
11 +
    case system = "System"
12 +
    case monospaced = "Monospaced"
13 +
    case serif = "Serif"
14 +
    case rounded = "Rounded"
15 +
16 +
    var id: String { rawValue }
17 +
18 +
    var fontDesign: Font.Design {
19 +
        switch self {
20 +
        case .system: return .default
21 +
        case .monospaced: return .monospaced
22 +
        case .serif: return .serif
23 +
        case .rounded: return .rounded
24 +
        }
25 +
    }
26 +
}
27 +
9 28
/// Observable object that manages theme customization settings.
10 29
/// This provides centralized accent color management that views can subscribe to.
11 30
class ThemeSettings: ObservableObject {
30 49
    /// The text color for content
31 50
    @Published var textColor: Color = Color(UIColor.label)
32 51
52 +
    /// The font design for content
53 +
    @Published var fontDesign: FontDesignOption = .monospaced
54 +
33 55
    /// The home page URL that the browser navigates to on launch and when pressing Home
34 56
    @AppStorage("homePage") var homePage: String = "gemini://geminiprotocol.net/"
35 57
37 59
    private static let accentColorKey = "accentColorHex"
38 60
    private static let backgroundColorKey = "backgroundColorHex"
39 61
    private static let textColorKey = "textColorHex"
62 +
    private static let fontDesignKey = "fontDesign"
40 63
41 64
    init() {
42 65
        if let hex = UserDefaults.standard.string(forKey: Self.accentColorKey),
51 74
           let color = Color(hex: hex) {
52 75
            textColor = color
53 76
        }
77 +
        if let fontRaw = UserDefaults.standard.string(forKey: Self.fontDesignKey),
78 +
           let font = FontDesignOption(rawValue: fontRaw) {
79 +
            fontDesign = font
80 +
        }
54 81
    }
55 82
56 83
    /// Sets all accent colors to the given color and persists the choice
80 107
        if let hex = color.toHex() {
81 108
            UserDefaults.standard.set(hex, forKey: Self.textColorKey)
82 109
        }
110 +
    }
111 +
112 +
    /// Sets the font design and persists the choice
113 +
    func setFontDesign(_ font: FontDesignOption) {
114 +
        fontDesign = font
115 +
        UserDefaults.standard.set(font.rawValue, forKey: Self.fontDesignKey)
83 116
    }
84 117
}
85 118
Titan/Views/SettingsView.swift +9 −1
13 13
    @State private var selectedAccentColor: Color = .blue
14 14
    @State private var selectedBackgroundColor: Color = Color(UIColor.systemBackground)
15 15
    @State private var selectedTextColor: Color = Color(UIColor.label)
16 +
    @State private var selectedFontDesign: FontDesignOption = .monospaced
16 17
17 18
    var body: some View {
18 19
        NavigationStack {
32 33
                    ColorPicker("Accent Color", selection: $selectedAccentColor, supportsOpacity: false)
33 34
                    ColorPicker("Background Color", selection: $selectedBackgroundColor, supportsOpacity: false)
34 35
                    ColorPicker("Text Color", selection: $selectedTextColor, supportsOpacity: false)
36 +
                    Picker("Font", selection: $selectedFontDesign) {
37 +
                        ForEach(FontDesignOption.allCases) { option in
38 +
                            Text(option.rawValue).tag(option)
39 +
                        }
40 +
                    }
35 41
                } header: {
36 42
                    Text("Appearance")
37 43
                } footer: {
38 -
                    Text("Customize the colors of your browser interface.")
44 +
                    Text("Customize the look of your browser interface.")
39 45
                }
40 46
            }
41 47
            .navigationTitle("Settings")
52 58
                        themeSettings.setAllAccentColors(selectedAccentColor)
53 59
                        themeSettings.setBackgroundColor(selectedBackgroundColor)
54 60
                        themeSettings.setTextColor(selectedTextColor)
61 +
                        themeSettings.setFontDesign(selectedFontDesign)
55 62
                        dismiss()
56 63
                    }
57 64
                }
61 68
                selectedAccentColor = themeSettings.accentColor
62 69
                selectedBackgroundColor = themeSettings.backgroundColor
63 70
                selectedTextColor = themeSettings.textColor
71 +
                selectedFontDesign = themeSettings.fontDesign
64 72
            }
65 73
        }
66 74
    }
Titan/Views/TitanContentView.swift +7 −7
76 76
        switch line {
77 77
        case .text(let text):
78 78
            Text(text)
79 -
                .font(.system(.body, design: .monospaced))
79 +
                .font(.system(.body, design: themeSettings.fontDesign.fontDesign))
80 80
                .foregroundColor(themeSettings.textColor)
81 81
82 82
        case .link(let url, let label):
84 84
                HStack(alignment:.top, spacing: 4) {
85 85
                    Text(label)
86 86
                        .multilineTextAlignment(.leading)
87 -
                        .font(.system(size: 14, design: .monospaced))
87 +
                        .font(.system(size: 14, design: themeSettings.fontDesign.fontDesign))
88 88
                }
89 89
            }
90 90
            .foregroundColor(themeSettings.linkColor)
92 92
93 93
        case .heading1(let text):
94 94
            Text(text)
95 -
                .font(.system(.title, design: .monospaced))
95 +
                .font(.system(.title, design: themeSettings.fontDesign.fontDesign))
96 96
                .fontWeight(.bold)
97 97
                .foregroundColor(themeSettings.textColor)
98 98
                .padding(.top, 8)
99 99
100 100
        case .heading2(let text):
101 101
            Text(text)
102 -
                .font(.system(.title2, design: .monospaced))
102 +
                .font(.system(.title2, design: themeSettings.fontDesign.fontDesign))
103 103
                .fontWeight(.semibold)
104 104
                .foregroundColor(themeSettings.textColor)
105 105
                .padding(.top, 6)
106 106
107 107
        case .heading3(let text):
108 108
            Text(text)
109 -
                .font(.system(.title3, design: .monospaced))
109 +
                .font(.system(.title3, design: themeSettings.fontDesign.fontDesign))
110 110
                .fontWeight(.medium)
111 111
                .foregroundColor(themeSettings.textColor)
112 112
                .padding(.top, 4)
116 116
                Text("\u{2022}")
117 117
                Text(text)
118 118
            }
119 -
            .font(.system(.body, design: .monospaced))
119 +
            .font(.system(.body, design: themeSettings.fontDesign.fontDesign))
120 120
            .foregroundColor(themeSettings.textColor)
121 121
122 122
        case .quote(let text):
123 123
            Text(text)
124 -
                .font(.system(.body, design: .monospaced))
124 +
                .font(.system(.body, design: themeSettings.fontDesign.fontDesign))
125 125
                .italic()
126 126
                .foregroundColor(.secondary)
127 127
                .padding(.leading, 12)