mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-04 10:53:33 +00:00
fix(ios): apply typography to native chrome
This commit is contained in:
@@ -65,8 +65,8 @@ struct AgentProDreamingDestination: View {
|
||||
OpenClawAdaptiveHeaderRow(
|
||||
title: "Dreaming",
|
||||
subtitle: self.dreamingDetail,
|
||||
titleFont: .title3.weight(.semibold),
|
||||
subtitleFont: .callout)
|
||||
titleFont: OpenClawType.title3SemiBold,
|
||||
subtitleFont: OpenClawType.subheadMedium)
|
||||
{
|
||||
OpenClawSidebarHeaderLeadingSlot(action: headerLeadingAction)
|
||||
} accessory: {
|
||||
|
||||
@@ -39,8 +39,8 @@ struct AgentProNodesDestination: View {
|
||||
OpenClawAdaptiveHeaderRow(
|
||||
title: "Instances",
|
||||
subtitle: self.instancesDetail,
|
||||
titleFont: .title3.weight(.semibold),
|
||||
subtitleFont: .callout)
|
||||
titleFont: OpenClawType.title3SemiBold,
|
||||
subtitleFont: OpenClawType.subheadMedium)
|
||||
{
|
||||
OpenClawSidebarHeaderLeadingSlot(action: headerLeadingAction)
|
||||
} accessory: {
|
||||
|
||||
@@ -172,8 +172,8 @@ extension AgentProTab {
|
||||
OpenClawAdaptiveHeaderRow(
|
||||
title: title,
|
||||
subtitle: subtitle,
|
||||
titleFont: .title3.weight(.semibold),
|
||||
subtitleFont: .callout)
|
||||
titleFont: OpenClawType.title3SemiBold,
|
||||
subtitleFont: OpenClawType.subheadMedium)
|
||||
{
|
||||
OpenClawSidebarHeaderLeadingSlot(action: headerLeadingAction)
|
||||
} accessory: {
|
||||
|
||||
@@ -8,8 +8,8 @@ extension AgentProTab {
|
||||
OpenClawAdaptiveHeaderRow(
|
||||
title: self.headerTitle,
|
||||
subtitle: "\(self.sortedAgents.count) total",
|
||||
titleFont: .system(size: 28, weight: .bold),
|
||||
subtitleFont: .subheadline,
|
||||
titleFont: OpenClawType.title2SemiBold,
|
||||
subtitleFont: OpenClawType.subheadMedium,
|
||||
subtitleLineLimit: 1)
|
||||
{
|
||||
if let headerLeadingAction {
|
||||
@@ -64,7 +64,9 @@ extension AgentProTab {
|
||||
HStack(spacing: 10) {
|
||||
Picker("Agent status", selection: self.$agentRosterFilter) {
|
||||
ForEach(AgentRosterFilter.allCases) { filter in
|
||||
Text(filter.title).tag(filter)
|
||||
Text(filter.title)
|
||||
.font(OpenClawType.captionSemiBold)
|
||||
.tag(filter)
|
||||
}
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
|
||||
@@ -120,8 +120,8 @@ struct CommandCenterTab: View {
|
||||
OpenClawAdaptiveHeaderRow(
|
||||
title: self.headerTitle,
|
||||
subtitle: self.gatewaySubtitle,
|
||||
titleFont: .title3.weight(.semibold),
|
||||
subtitleFont: .caption,
|
||||
titleFont: OpenClawType.title3SemiBold,
|
||||
subtitleFont: OpenClawType.caption,
|
||||
subtitleLineLimit: 1)
|
||||
{
|
||||
if let headerLeadingAction {
|
||||
|
||||
@@ -51,8 +51,8 @@ struct OpenClawDocsScreen: View {
|
||||
OpenClawAdaptiveHeaderRow(
|
||||
title: "Docs",
|
||||
subtitle: "Gateway setup, pairing, channels, and mobile node reference.",
|
||||
titleFont: .headline,
|
||||
subtitleFont: .caption)
|
||||
titleFont: OpenClawType.headline,
|
||||
subtitleFont: OpenClawType.caption)
|
||||
{
|
||||
HStack(alignment: .top, spacing: 12) {
|
||||
if let headerLeadingAction {
|
||||
|
||||
@@ -151,6 +151,39 @@ enum OpenClawType {
|
||||
Mono.semiBold,
|
||||
]
|
||||
|
||||
@MainActor
|
||||
static func installUIKitAppearance() {
|
||||
let inlineNavigationTitleFont = self.scaledDisplayUIFont(
|
||||
weight: Display.opticalSemiBold,
|
||||
size: 17,
|
||||
relativeTo: .headline)
|
||||
let largeNavigationTitleFont = self.scaledDisplayUIFont(
|
||||
weight: Display.heavyTitle,
|
||||
size: 34,
|
||||
relativeTo: .largeTitle)
|
||||
let tabBarNormalFont = self.scaledBodyUIFont(weight: Body.medium, size: 11, relativeTo: .caption2)
|
||||
let tabBarSelectedFont = self.scaledBodyUIFont(weight: Body.semiBold, size: 11, relativeTo: .caption2)
|
||||
let segmentedNormalFont = self.scaledBodyUIFont(weight: Body.medium, size: 13, relativeTo: .footnote)
|
||||
let segmentedSelectedFont = self.scaledBodyUIFont(weight: Body.semiBold, size: 13, relativeTo: .footnote)
|
||||
|
||||
let navigationBar = UINavigationBar.appearance()
|
||||
var titleAttributes = navigationBar.titleTextAttributes ?? [:]
|
||||
titleAttributes[.font] = inlineNavigationTitleFont
|
||||
navigationBar.titleTextAttributes = titleAttributes
|
||||
|
||||
var largeTitleAttributes = navigationBar.largeTitleTextAttributes ?? [:]
|
||||
largeTitleAttributes[.font] = largeNavigationTitleFont
|
||||
navigationBar.largeTitleTextAttributes = largeTitleAttributes
|
||||
|
||||
let tabBarItem = UITabBarItem.appearance()
|
||||
tabBarItem.setTitleTextAttributes([.font: tabBarNormalFont], for: .normal)
|
||||
tabBarItem.setTitleTextAttributes([.font: tabBarSelectedFont], for: .selected)
|
||||
|
||||
let segmentedControl = UISegmentedControl.appearance()
|
||||
segmentedControl.setTitleTextAttributes([.font: segmentedNormalFont], for: .normal)
|
||||
segmentedControl.setTitleTextAttributes([.font: segmentedSelectedFont], for: .selected)
|
||||
}
|
||||
|
||||
private enum Display {
|
||||
static let postScriptName = "RedHatDisplay-Regular"
|
||||
static let opticalSemiBold: CGFloat = 650
|
||||
@@ -181,11 +214,11 @@ enum OpenClawType {
|
||||
size: CGFloat,
|
||||
relativeTo textStyle: UIFont.TextStyle) -> Font
|
||||
{
|
||||
self.scaledVariableFont(
|
||||
name: Display.postScriptName,
|
||||
size: size,
|
||||
relativeTo: textStyle,
|
||||
variations: [self.fontWeightAxis: weight])
|
||||
Font(
|
||||
self.scaledDisplayUIFont(
|
||||
weight: weight,
|
||||
size: size,
|
||||
relativeTo: textStyle))
|
||||
}
|
||||
|
||||
private static func scaledBody(
|
||||
@@ -193,14 +226,11 @@ enum OpenClawType {
|
||||
size: CGFloat,
|
||||
relativeTo textStyle: UIFont.TextStyle) -> Font
|
||||
{
|
||||
self.scaledVariableFont(
|
||||
name: Body.postScriptName,
|
||||
size: size,
|
||||
relativeTo: textStyle,
|
||||
variations: [
|
||||
self.fontWeightAxis: weight,
|
||||
self.opticalSizeAxis: min(max(size, 14), 32),
|
||||
])
|
||||
Font(
|
||||
self.scaledBodyUIFont(
|
||||
weight: weight,
|
||||
size: size,
|
||||
relativeTo: textStyle))
|
||||
}
|
||||
|
||||
private static func scaledMono(
|
||||
@@ -211,16 +241,42 @@ enum OpenClawType {
|
||||
self.scaledFont(name: name, size: size, relativeTo: textStyle)
|
||||
}
|
||||
|
||||
private static func scaledVariableFont(
|
||||
private static func scaledDisplayUIFont(
|
||||
weight: CGFloat,
|
||||
size: CGFloat,
|
||||
relativeTo textStyle: UIFont.TextStyle) -> UIFont
|
||||
{
|
||||
self.scaledVariableUIFont(
|
||||
name: Display.postScriptName,
|
||||
size: size,
|
||||
relativeTo: textStyle,
|
||||
variations: [self.fontWeightAxis: weight])
|
||||
}
|
||||
|
||||
private static func scaledBodyUIFont(
|
||||
weight: CGFloat,
|
||||
size: CGFloat,
|
||||
relativeTo textStyle: UIFont.TextStyle) -> UIFont
|
||||
{
|
||||
self.scaledVariableUIFont(
|
||||
name: Body.postScriptName,
|
||||
size: size,
|
||||
relativeTo: textStyle,
|
||||
variations: [
|
||||
self.fontWeightAxis: weight,
|
||||
self.opticalSizeAxis: min(max(size, 14), 32),
|
||||
])
|
||||
}
|
||||
|
||||
private static func scaledVariableUIFont(
|
||||
name: String,
|
||||
size: CGFloat,
|
||||
relativeTo textStyle: UIFont.TextStyle,
|
||||
variations: [NSNumber: CGFloat]) -> Font
|
||||
variations: [NSNumber: CGFloat]) -> UIFont
|
||||
{
|
||||
guard UIFont(name: name, size: size) != nil else {
|
||||
let fallback = UIFont.systemFont(ofSize: size)
|
||||
let scaledFallback = UIFontMetrics(forTextStyle: textStyle).scaledFont(for: fallback)
|
||||
return Font(scaledFallback)
|
||||
return UIFontMetrics(forTextStyle: textStyle).scaledFont(for: fallback)
|
||||
}
|
||||
|
||||
let descriptor = UIFontDescriptor(fontAttributes: [
|
||||
@@ -228,8 +284,7 @@ enum OpenClawType {
|
||||
kCTFontVariationAttribute as UIFontDescriptor.AttributeName: variations,
|
||||
])
|
||||
let base = UIFont(descriptor: descriptor, size: size)
|
||||
let scaled = UIFontMetrics(forTextStyle: textStyle).scaledFont(for: base)
|
||||
return Font(scaled)
|
||||
return UIFontMetrics(forTextStyle: textStyle).scaledFont(for: base)
|
||||
}
|
||||
|
||||
private static func scaledFont(
|
||||
|
||||
@@ -33,6 +33,8 @@ struct RootTabsPhoneControlHub: View {
|
||||
} header: {
|
||||
if let title = self.sectionTitle(for: group) {
|
||||
Text(title)
|
||||
.font(OpenClawType.captionSemiBold)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ extension SettingsProTab {
|
||||
route: .voice)
|
||||
}
|
||||
|
||||
Section("Device") {
|
||||
Section {
|
||||
self.appearanceRow
|
||||
self.settingsListRow(
|
||||
icon: "stethoscope",
|
||||
@@ -166,6 +166,10 @@ extension SettingsProTab {
|
||||
icon: "info.circle",
|
||||
title: "About",
|
||||
route: .about)
|
||||
} header: {
|
||||
Text("Device")
|
||||
.font(OpenClawType.captionSemiBold)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Section {
|
||||
|
||||
@@ -628,6 +628,7 @@ struct OpenClawApp: App {
|
||||
init() {
|
||||
Self.installUncaughtExceptionLogger()
|
||||
GatewaySettingsStore.bootstrapPersistence()
|
||||
OpenClawType.installUIKitAppearance()
|
||||
let appModel = NodeAppModel()
|
||||
#if DEBUG
|
||||
if ProcessInfo.processInfo.arguments.contains("--openclaw-reset-onboarding") {
|
||||
@@ -658,6 +659,7 @@ struct OpenClawApp: App {
|
||||
WindowGroup {
|
||||
RootTabs()
|
||||
.tint(OpenClawBrand.accent)
|
||||
.font(OpenClawType.body)
|
||||
.preferredColorScheme(self.appearancePreference.colorScheme)
|
||||
.environment(self.appModel)
|
||||
.environment(self.appModel.voiceWake)
|
||||
|
||||
@@ -244,7 +244,7 @@ struct RootTabsSourceGuardTests {
|
||||
from: "var appearanceRow: some View",
|
||||
to: "var appearanceRowLabel: some View")
|
||||
|
||||
#expect(gatewayStatus.contains("HStack(spacing: 6)"))
|
||||
#expect(gatewayStatus.contains("OpenClawStatusBadge(label: self.title, tone: self.tone)"))
|
||||
#expect(!gatewayStatus.contains("ProCapsule("))
|
||||
#expect(!gatewayStatus.contains("Capsule()"))
|
||||
#expect(agentDestinationsSource.contains("List {"))
|
||||
@@ -259,7 +259,8 @@ struct RootTabsSourceGuardTests {
|
||||
#expect(!talkSource.contains("conversationCard"))
|
||||
#expect(!talkSource.contains("voiceModeCard"))
|
||||
#expect(!talkSource.contains("statusChip"))
|
||||
#expect(settingsList.contains("Section(\"Device\")"))
|
||||
#expect(settingsList.contains("Text(\"Device\")"))
|
||||
#expect(settingsList.contains(".font(OpenClawType.captionSemiBold)"))
|
||||
#expect(!settingsList.contains("ProCard("))
|
||||
#expect(settingsRow.contains("NavigationLink(value: route)"))
|
||||
#expect(!settingsRow.contains("chevron.right"))
|
||||
|
||||
Reference in New Issue
Block a user