Files
Sybil-2/ios/Packages/Sybil/Sources/Sybil/SybilTheme.swift
2026-05-02 16:23:00 -07:00

195 lines
5.8 KiB
Swift

import CoreText
import Foundation
import SwiftUI
enum SybilFontRegistry {
static func registerIfNeeded() {
_ = registeredFonts
}
private static let registeredFonts: Void = {
for fontName in ["Inter", "Orbitron"] {
guard let url = Bundle.main.url(forResource: fontName, withExtension: "ttf", subdirectory: "Fonts") ??
Bundle.main.url(forResource: fontName, withExtension: "ttf")
else {
continue
}
CTFontManagerRegisterFontsForURL(url as CFURL, .process, nil)
}
}()
}
extension Font {
static func sybil(_ textStyle: Font.TextStyle, weight: Font.Weight = .regular) -> Font {
SybilFontRegistry.registerIfNeeded()
return .custom("Inter", size: Self.sybilPointSize(for: textStyle), relativeTo: textStyle)
.weight(weight)
}
static func sybil(size: CGFloat, weight: Font.Weight = .regular) -> Font {
SybilFontRegistry.registerIfNeeded()
return .custom("Inter", size: size)
.weight(weight)
}
private static func sybilPointSize(for textStyle: Font.TextStyle) -> CGFloat {
switch textStyle {
case .largeTitle:
return 34
case .title:
return 28
case .title2:
return 22
case .title3:
return 20
case .headline:
return 17
case .subheadline:
return 15
case .callout:
return 16
case .caption:
return 12
case .caption2:
return 11
case .footnote:
return 13
case .body:
return 17
@unknown default:
return 17
}
}
}
enum SybilTheme {
static let background = Color(red: 0.02, green: 0.02, blue: 0.05)
static let surface = Color(red: 0.05, green: 0.04, blue: 0.10)
static let surfaceStrong = Color(red: 0.07, green: 0.06, blue: 0.14)
static let card = Color(red: 0.06, green: 0.05, blue: 0.12)
static let border = Color(red: 0.24, green: 0.20, blue: 0.38)
static let primary = Color(red: 0.57, green: 0.38, blue: 0.96)
static let primarySoft = Color(red: 0.43, green: 0.25, blue: 0.76)
static let accent = Color(red: 0.31, green: 0.88, blue: 0.95)
static let text = Color(red: 0.96, green: 0.94, blue: 1.0)
static let textMuted = Color(red: 0.65, green: 0.62, blue: 0.76)
static let searchCard = Color(red: 0.07, green: 0.06, blue: 0.14)
static let userBubble = Color(red: 0.29, green: 0.13, blue: 0.65)
static let danger = Color(red: 0.96, green: 0.32, blue: 0.40)
static var backgroundGradient: LinearGradient {
LinearGradient(
colors: [
Color(red: 0.12, green: 0.08, blue: 0.28),
Color(red: 0.04, green: 0.03, blue: 0.09),
background
],
startPoint: .top,
endPoint: .bottom
)
}
static var brandGradient: LinearGradient {
LinearGradient(
colors: [
Color(red: 1.0, green: 0.55, blue: 0.97),
Color(red: 0.60, green: 0.43, blue: 1.0),
Color(red: 0.40, green: 0.87, blue: 1.0)
],
startPoint: .leading,
endPoint: .trailing
)
}
static var panelGradient: LinearGradient {
LinearGradient(
colors: [
Color(red: 0.07, green: 0.06, blue: 0.15).opacity(0.94),
Color(red: 0.03, green: 0.03, blue: 0.08).opacity(0.96)
],
startPoint: .top,
endPoint: .bottom
)
}
static var primaryGradient: LinearGradient {
LinearGradient(
colors: [
Color(red: 0.43, green: 0.27, blue: 0.92),
Color(red: 0.45, green: 0.09, blue: 0.63)
],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
}
static var selectedRowGradient: LinearGradient {
LinearGradient(
colors: [
primary.opacity(0.56),
primarySoft.opacity(0.48)
],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
}
static var userBubbleGradient: LinearGradient {
LinearGradient(
colors: [
Color(red: 0.38, green: 0.16, blue: 0.80),
Color(red: 0.25, green: 0.08, blue: 0.55)
],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
}
static var composerGradient: LinearGradient {
LinearGradient(
colors: [
Color(red: 0.04, green: 0.04, blue: 0.10).opacity(0.98),
Color(red: 0.09, green: 0.06, blue: 0.16).opacity(0.94)
],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
}
static var toolCallGradient: LinearGradient {
LinearGradient(
colors: [
Color(red: 0.01, green: 0.15, blue: 0.17).opacity(0.70),
Color(red: 0.03, green: 0.09, blue: 0.15).opacity(0.78)
],
startPoint: .leading,
endPoint: .trailing
)
}
static var failedToolCallGradient: LinearGradient {
LinearGradient(
colors: [
danger.opacity(0.18),
Color(red: 0.15, green: 0.03, blue: 0.07).opacity(0.72)
],
startPoint: .leading,
endPoint: .trailing
)
}
}
struct SybilWordmark: View {
var size: CGFloat = 30
var body: some View {
Text("SYBIL")
.font(.custom("Orbitron", size: size))
.fontWeight(.black)
.tracking(0)
.foregroundStyle(SybilTheme.brandGradient)
.accessibilityLabel("Sybil")
}
}