Library design: cards + redesigned list on the bookmarks screen, tag picker sheet #9

Merged
admin merged 11 commits from feat/library-browse-prototype into master 2026-07-30 04:03:03 +00:00
2 changed files with 64 additions and 3 deletions
Showing only changes of commit dd1c09a00c - Show all commits
+2
View File
@@ -12,6 +12,8 @@ private let defaultConfig = ServerConfig(
struct MarksApp: App {
@State private var serverConfig: ServerConfig = ServerConfig.load() ?? defaultConfig
init() { PaperAppearance.apply() }
var body: some Scene {
WindowGroup {
MainContainer(config: serverConfig) {
+62 -3
View File
@@ -83,11 +83,20 @@ enum Paper {
}
static func dynamic(light: UInt32, dark: UInt32) -> Color {
Color(uiColor: UIColor { traits in
UIColor(rgb: traits.userInterfaceStyle == .dark ? dark : light)
})
Color(uiColor: dynamicUI(light: light, dark: dark))
}
static func dynamicUI(light: UInt32, dark: UInt32) -> UIColor {
UIColor { traits in
UIColor(rgb: traits.userInterfaceStyle == .dark ? dark : light)
}
}
/// UIKit equivalents, for the chrome SwiftUI can't reach chiefly the
/// navigation bar, whose title font has no SwiftUI API at all.
static let uiSheet = dynamicUI(light: 0xF8F5EF, dark: 0x15130F)
static let uiInk = dynamicUI(light: 0x14110C, dark: 0xF1ECE1)
static func luminance(of hex: UInt32) -> Double {
let r = Double((hex >> 16) & 0xFF) / 255
let g = Double((hex >> 8) & 0xFF) / 255
@@ -154,6 +163,56 @@ extension View {
}
}
// MARK: - UIKit chrome
/// The navigation and tab bars are UIKit underneath, and their fonts have no
/// SwiftUI equivalent `navigationTitle` will render in the system bold sans
/// whatever you do to the view. Both are configured once at launch so screen
/// titles speak the same serif as the content beneath them.
enum PaperAppearance {
static func apply() {
let bar = UINavigationBarAppearance()
// Transparent, not opaque: the screens already paint the paper ground
// themselves, and an opaque bar config stops iOS 26 laying out the
// large title at all.
bar.configureWithTransparentBackground()
bar.largeTitleTextAttributes = [
.font: serif(34, weight: .regular),
.foregroundColor: Paper.uiInk,
]
bar.titleTextAttributes = [
.font: serif(17, weight: .medium),
.foregroundColor: Paper.uiInk,
]
UINavigationBar.appearance().standardAppearance = bar
UINavigationBar.appearance().compactAppearance = bar
UINavigationBar.appearance().scrollEdgeAppearance = bar
let tabs = UITabBarAppearance()
tabs.configureWithDefaultBackground()
let label: [NSAttributedString.Key: Any] = [
.font: UIFont.monospacedSystemFont(ofSize: 10, weight: .medium)
]
for item in [tabs.stackedLayoutAppearance,
tabs.inlineLayoutAppearance,
tabs.compactInlineLayoutAppearance] {
item.normal.titleTextAttributes = label
item.selected.titleTextAttributes = label
}
UITabBar.appearance().standardAppearance = tabs
UITabBar.appearance().scrollEdgeAppearance = tabs
}
/// `withDesign(.serif)` is the only route to the system serif in UIKit, and
/// it returns nil if the design is unavailable fall back rather than
/// force-unwrap a font.
private static func serif(_ size: CGFloat, weight: UIFont.Weight) -> UIFont {
let base = UIFont.systemFont(ofSize: size, weight: weight)
guard let descriptor = base.fontDescriptor.withDesign(.serif) else { return base }
return UIFont(descriptor: descriptor, size: size)
}
}
// MARK: - Empty state
/// The paper equivalent of `ContentUnavailableView`, which can't be restyled