font size setting

This commit is contained in:
Ian Gulliver
2026-10-20 19:32:27 -07:00
parent f2188c53eb
commit adb9424e66
9 changed files with 95 additions and 4 deletions
+1
View File
@@ -1638,6 +1638,7 @@ private struct RunSummary: View {
}
}
@MainActor
private func styled(_ parts: [(String, CGFloat, Color?)], size: CGFloat = 12) -> AttributedString {
var out = AttributedString()
for (text, weight, color) in parts {
+3
View File
@@ -277,10 +277,12 @@ struct DiagramLayout {
let size: CGSize
}
@MainActor
private var labelFont: CTFont {
Fonts.ns(13) as CTFont
}
@MainActor
private var edgeFont: CTFont {
Fonts.ns(12) as CTFont
}
@@ -296,6 +298,7 @@ func textSize(_ text: String, _ font: CTFont) -> CGSize {
return CGSize(width: ceil(width), height: ceil(lineHeight * CGFloat(lines.count)))
}
@MainActor
func layoutFlowchart(_ chart: Flowchart) -> DiagramLayout {
let ids = chart.order
var succ: [String: [String]] = [:]
+39
View File
@@ -1,7 +1,41 @@
import CoreText
import Foundation
import Synchronization
import SwiftData
import SwiftUI
@MainActor
@Observable
final class FontSize {
static let shared = FontSize()
static let range = 9...20
private(set) var body = PrefsRecord.defaultFontSize
private init() {
load()
}
func load() {
body = record()?.fontSize ?? PrefsRecord.defaultFontSize
}
func set(_ size: Int) {
if let r = record() {
r.fontSize = size
r.saved = Date()
} else {
persistence.insert(PrefsRecord(fontSize: size))
}
saveRecords()
body = size
}
private func record() -> PrefsRecord? {
fetchRecords(FetchDescriptor<PrefsRecord>(sortBy: [SortDescriptor(\.saved, order: .reverse)])).first
}
}
enum Fonts {
private static func file(_ subset: String, _ italic: Bool, _ weight: CGFloat) -> CTFontDescriptor {
let url = Bundle.main.resourceURL!.appending(path: "fonts/atkinson-hyperlegible-mono-\(subset)-wght-\(italic ? "italic" : "normal").woff2")
@@ -17,7 +51,10 @@ enum Fonts {
private static let fonts = Mutex<[String: CTFont]>([:])
// Call sites give sizes relative to a 13pt body; the user's font size shifts them all.
@MainActor
private static func cached(_ size: CGFloat, _ weight: CGFloat, _ italic: Bool) -> CTFont {
let size = size + CGFloat(FontSize.shared.body - 13)
let key = "\(size) \(weight) \(italic)"
return fonts.withLock { fonts in
if let f = fonts[key] {
@@ -29,10 +66,12 @@ enum Fonts {
}
}
@MainActor
static func font(_ size: CGFloat, weight: CGFloat = 400, italic: Bool = false) -> Font {
Font(cached(size, weight, italic))
}
@MainActor
static func ns(_ size: CGFloat, weight: CGFloat = 400, italic: Bool = false) -> NSFont {
cached(size, weight, italic) as NSFont
}
+14 -1
View File
@@ -38,8 +38,21 @@ final class VisitRecord {
}
}
@Model
final class PrefsRecord {
static let defaultFontSize = 12
var fontSize = PrefsRecord.defaultFontSize
var saved = Date.distantPast
init(fontSize: Int) {
self.fontSize = fontSize
saved = Date()
}
}
private let container: ModelContainer = {
let schema = Schema([ServerRecord.self, DraftRecord.self, VisitRecord.self])
let schema = Schema([ServerRecord.self, DraftRecord.self, VisitRecord.self, PrefsRecord.self])
let dir = URL.applicationSupportDirectory.appending(path: "run.fc.byre.mac", directoryHint: .isDirectory)
do {
try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
+27 -1
View File
@@ -27,6 +27,11 @@ struct SettingsView: View {
.foregroundStyle(Palette.muted)
.fixedSize(horizontal: false, vertical: true)
ServerColorPicker()
heading("Font size")
Text("The size of body text, on every Mac you use. Other text grows and shrinks with it.")
.foregroundStyle(Palette.muted)
.fixedSize(horizontal: false, vertical: true)
FontSizeStepper()
heading("Notifications")
DeviceNotifications()
PrefsBox()
@@ -87,12 +92,33 @@ private struct ServerColorPicker: View {
}
}
private struct FontSizeStepper: View {
var body: some View {
let fonts = FontSize.shared
HStack(spacing: 8) {
Button("−") {
fonts.set(fonts.body - 1)
}
.buttonStyle(WebButtonStyle())
.disabled(fonts.body <= FontSize.range.lowerBound)
Text("\(fonts.body) pt")
.monospacedDigit()
Button("+") {
fonts.set(fonts.body + 1)
}
.buttonStyle(WebButtonStyle())
.disabled(fonts.body >= FontSize.range.upperBound)
}
.padding(.top, 8)
}
}
private struct SyncState: View {
var body: some View {
TimelineView(.periodic(from: .now, by: 30)) { _ in
if let sync = Servers.shared.sync {
if sync.ok {
Text("This Mac shares its servers, window colours, drafts and task visits through iCloud. Last synced \(ago(sync.at)).")
Text("This Mac shares its servers, window colours, font size, drafts and task visits through iCloud. Last synced \(ago(sync.at)).")
.fixedSize(horizontal: false, vertical: true)
} else {
Text("iCloud sync is failing on this Mac, so changes made here aren't reaching your other Macs. Failed \(ago(sync.at)): \(sync.error ?? "")")
+1
View File
@@ -34,6 +34,7 @@ final class Servers {
connection.store?.drafts?.reload()
}
load()
FontSize.shared.load()
}
}
}
+4
View File
@@ -90,6 +90,10 @@ struct TerminalHost: NSViewRepresentable {
}
func updateNSView(_ nsView: TerminalView, context: Context) {
let font = Fonts.ns(13)
if nsView.font !== font {
nsView.font = font
}
if context.coordinator.scheme == scheme {
return
}