Merge 6e5af48e4f4671ffa061b50b774f5e404067d0f6 into 948d6a85b9f254760c475a64f02fe8899e4f3d7f

This commit is contained in:
pranavharshith 2026-08-01 10:46:11 +02:00 committed by GitHub
commit 15a882b17e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 1048 additions and 24 deletions

View File

@ -3210,6 +3210,931 @@
}
}
},
"app_info.appearance.nord" : {
"extractionState" : "manual",
"localizations" : {
"ar" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"bn" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"es" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"fa" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"fil" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"he" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"hi" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"id" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"ms" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"ne" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"nl" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"pt" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"pt-BR" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"ru" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"sv" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"ta" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"th" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"tr" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"uk" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"ur" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"vi" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "nord"
}
}
}
},
"app_info.appearance.dracula" : {
"extractionState" : "manual",
"localizations" : {
"ar" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"bn" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"es" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"fa" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"fil" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"he" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"hi" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"id" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"ms" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"ne" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"nl" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"pt" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"pt-BR" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"ru" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"sv" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"ta" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"th" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"tr" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"uk" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"ur" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"vi" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "dracula"
}
}
}
},
"app_info.appearance.solarized_dark" : {
"extractionState" : "manual",
"localizations" : {
"ar" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"bn" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"es" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"fa" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"fil" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"he" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"hi" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"id" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"ms" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"ne" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"nl" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"pt" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"pt-BR" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"ru" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"sv" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"ta" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"th" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"tr" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"uk" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"ur" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"vi" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "solarized dark"
}
}
}
},
"app_info.appearance.tokyo_night" : {
"extractionState" : "manual",
"localizations" : {
"ar" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"bn" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"es" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"fa" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"fil" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"he" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"hi" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"id" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"ms" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"ne" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"nl" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"pt" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"pt-BR" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"ru" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"sv" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"ta" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"th" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"tr" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"uk" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"ur" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"vi" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "tokyo night"
}
}
}
},
"app_info.appearance.monochrome" : {
"extractionState" : "manual",
"localizations" : {
"ar" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"bn" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"es" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"fa" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"fil" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"he" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"hi" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"id" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"ms" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"ne" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"nl" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"pt" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"pt-BR" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"ru" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"sv" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"ta" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"th" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"tr" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"uk" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"ur" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"vi" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "monochrome"
}
}
}
},
"app_info.appearance.title" : {
"extractionState" : "manual",
"localizations" : {

View File

@ -12,6 +12,11 @@ import SwiftUI
enum AppTheme: String, CaseIterable, Identifiable {
case matrix
case liquidGlass
case nord
case dracula
case solarizedDark
case tokyoNight
case monochrome
var id: String { rawValue }
@ -22,6 +27,11 @@ enum AppTheme: String, CaseIterable, Identifiable {
switch self {
case .matrix: return "app_info.appearance.matrix"
case .liquidGlass: return "app_info.appearance.liquid_glass"
case .nord: return "app_info.appearance.nord"
case .dracula: return "app_info.appearance.dracula"
case .solarizedDark: return "app_info.appearance.solarized_dark"
case .tokyoNight: return "app_info.appearance.tokyo_night"
case .monochrome: return "app_info.appearance.monochrome"
}
}
@ -31,13 +41,21 @@ enum AppTheme: String, CaseIterable, Identifiable {
switch self {
case .matrix: return .monospaced
case .liquidGlass: return .default
case .nord: return .default
case .dracula: return .monospaced
case .solarizedDark: return .monospaced
case .tokyoNight: return .default
case .monochrome: return .default
}
}
/// Whether chrome surfaces (header/composer bars, input field) render as
/// translucent glass/material instead of the flat matrix background.
var usesGlassChrome: Bool {
self == .liquidGlass
switch self {
case .liquidGlass: return true
case .matrix, .nord, .dracula, .solarizedDark, .tokyoNight, .monochrome: return false
}
}
/// Discriminator mixed into per-message formatting caches so cached
@ -47,16 +65,24 @@ enum AppTheme: String, CaseIterable, Identifiable {
switch self {
case .matrix: return ""
case .liquidGlass: return "lg:"
case .nord: return "nd:"
case .dracula: return "dc:"
case .solarizedDark: return "sd:"
case .tokyoNight: return "tn:"
case .monochrome: return "mc:"
}
}
/// Resolves the semantic color palette for this theme under the given color scheme.
func palette(for colorScheme: ColorScheme) -> ThemePalette {
switch self {
case .matrix:
return .matrix(colorScheme)
case .liquidGlass:
return .liquidGlass(colorScheme)
case .matrix: return .matrix(colorScheme)
case .liquidGlass: return .liquidGlass(colorScheme)
case .nord: return .nord(colorScheme)
case .dracula: return .dracula(colorScheme)
case .solarizedDark: return .solarizedDark(colorScheme)
case .tokyoNight: return .tokyoNight(colorScheme)
case .monochrome: return .monochrome(colorScheme)
}
}
}
@ -109,6 +135,76 @@ struct ThemePalette {
)
}
static func nord(_ colorScheme: ColorScheme) -> ThemePalette {
let isDark = colorScheme == .dark
return ThemePalette(
background: isDark ? Color(red: 0.18, green: 0.20, blue: 0.25) : Color(red: 0.93, green: 0.94, blue: 0.96),
primary: isDark ? Color(red: 0.93, green: 0.94, blue: 0.96) : Color(red: 0.18, green: 0.20, blue: 0.25),
secondary: isDark ? Color(red: 0.61, green: 0.66, blue: 0.74) : Color(red: 0.30, green: 0.34, blue: 0.40),
accent: isDark ? Color(red: 0.53, green: 0.75, blue: 0.82) : Color(red: 0.37, green: 0.51, blue: 0.67),
locationAccent: isDark ? Color(red: 0.64, green: 0.75, blue: 0.55) : Color(red: 0.40, green: 0.55, blue: 0.31),
accentBlue: isDark ? Color(red: 0.51, green: 0.63, blue: 0.76) : Color(red: 0.51, green: 0.63, blue: 0.76),
alertRed: isDark ? Color(red: 0.75, green: 0.38, blue: 0.42) : Color(red: 0.75, green: 0.38, blue: 0.42),
divider: isDark ? Color(red: 0.30, green: 0.34, blue: 0.40) : Color(red: 0.85, green: 0.87, blue: 0.91)
)
}
static func dracula(_ colorScheme: ColorScheme) -> ThemePalette {
let isDark = colorScheme == .dark
return ThemePalette(
background: isDark ? Color(red: 0.16, green: 0.16, blue: 0.21) : Color(red: 0.97, green: 0.97, blue: 0.95),
primary: isDark ? Color(red: 0.97, green: 0.97, blue: 0.95) : Color(red: 0.16, green: 0.16, blue: 0.21),
secondary: isDark ? Color(red: 0.38, green: 0.45, blue: 0.64) : Color(red: 0.38, green: 0.45, blue: 0.64),
accent: isDark ? Color(red: 1.0, green: 0.47, blue: 0.78) : Color(red: 0.80, green: 0.28, blue: 0.56),
locationAccent: isDark ? Color(red: 0.31, green: 0.98, blue: 0.48) : Color(red: 0.22, green: 0.60, blue: 0.33),
accentBlue: isDark ? Color(red: 0.55, green: 0.91, blue: 0.99) : Color(red: 0.27, green: 0.73, blue: 0.83),
alertRed: isDark ? Color(red: 1.0, green: 0.33, blue: 0.33) : Color(red: 0.82, green: 0.18, blue: 0.18),
divider: isDark ? Color(red: 0.27, green: 0.28, blue: 0.35) : Color(red: 0.88, green: 0.88, blue: 0.88)
)
}
static func solarizedDark(_ colorScheme: ColorScheme) -> ThemePalette {
let isDark = colorScheme == .dark
return ThemePalette(
background: isDark ? Color(red: 0.0, green: 0.17, blue: 0.21) : Color(red: 0.99, green: 0.96, blue: 0.89),
primary: isDark ? Color(red: 0.51, green: 0.58, blue: 0.59) : Color(red: 0.40, green: 0.48, blue: 0.51),
secondary: isDark ? Color(red: 0.40, green: 0.48, blue: 0.51) : Color(red: 0.51, green: 0.58, blue: 0.59),
accent: isDark ? Color(red: 0.16, green: 0.63, blue: 0.60) : Color(red: 0.16, green: 0.63, blue: 0.60),
locationAccent: isDark ? Color(red: 0.52, green: 0.60, blue: 0.0) : Color(red: 0.52, green: 0.60, blue: 0.0),
accentBlue: isDark ? Color(red: 0.15, green: 0.55, blue: 0.82) : Color(red: 0.15, green: 0.55, blue: 0.82),
alertRed: isDark ? Color(red: 0.86, green: 0.20, blue: 0.18) : Color(red: 0.86, green: 0.20, blue: 0.18),
divider: isDark ? Color(red: 0.03, green: 0.24, blue: 0.26) : Color(red: 0.93, green: 0.91, blue: 0.84)
)
}
static func tokyoNight(_ colorScheme: ColorScheme) -> ThemePalette {
let isDark = colorScheme == .dark
return ThemePalette(
background: isDark ? Color(red: 0.10, green: 0.11, blue: 0.15) : Color(red: 0.84, green: 0.84, blue: 0.86),
primary: isDark ? Color(red: 0.66, green: 0.69, blue: 0.84) : Color(red: 0.22, green: 0.38, blue: 0.75),
secondary: isDark ? Color(red: 0.47, green: 0.51, blue: 0.67) : Color(red: 0.36, green: 0.38, blue: 0.56),
accent: isDark ? Color(red: 0.49, green: 0.81, blue: 1.0) : Color(red: 0.18, green: 0.49, blue: 0.91),
locationAccent: isDark ? Color(red: 0.62, green: 0.81, blue: 0.42) : Color(red: 0.35, green: 0.46, blue: 0.22),
accentBlue: isDark ? Color(red: 0.48, green: 0.64, blue: 0.97) : Color(red: 0.18, green: 0.49, blue: 0.91),
alertRed: isDark ? Color(red: 0.97, green: 0.46, blue: 0.56) : Color(red: 0.78, green: 0.26, blue: 0.26),
divider: isDark ? Color(red: 0.18, green: 0.24, blue: 0.39) : Color(red: 0.71, green: 0.71, blue: 0.77)
)
}
static func monochrome(_ colorScheme: ColorScheme) -> ThemePalette {
let isDark = colorScheme == .dark
return ThemePalette(
background: isDark ? .black : .white,
primary: isDark ? .white : .black,
secondary: isDark ? Color(white: 0.65) : Color(white: 0.40),
accent: isDark ? .white : .black,
locationAccent: isDark ? Color(white: 0.75) : Color(white: 0.25),
accentBlue: isDark ? Color(white: 0.75) : Color(white: 0.25),
alertRed: isDark ? Color(red: 0.82, green: 0.32, blue: 0.32) : Color(red: 0.72, green: 0.18, blue: 0.18),
divider: isDark ? Color(white: 0.25) : Color(white: 0.80)
)
}
private static var systemBackground: Color {
#if os(iOS)
Color(UIColor.systemBackground)

View File

@ -333,27 +333,30 @@ struct AppInfoView: View {
@ViewBuilder
private var settingsContent: some View {
VStack(alignment: .leading, spacing: 24) {
// Appearance single row: label left, theme chips right
HStack(spacing: 12) {
// Appearance label above theme chips (scrollable for many themes)
VStack(alignment: .leading, spacing: 8) {
SectionHeader(Strings.appearanceTitle)
Spacer()
ForEach(AppTheme.allCases) { theme in
Button {
appThemeRawValue = theme.rawValue
} label: {
Text(theme.displayNameKey)
.bitchatFont(size: 13, weight: selectedTheme == theme ? .semibold : .regular)
.foregroundColor(selectedTheme == theme ? palette.accent : secondaryTextColor)
.padding(.horizontal, 10)
.padding(.vertical, 6)
.background(
RoundedRectangle(cornerRadius: 8, style: .continuous)
.fill(selectedTheme == theme ? palette.accent.opacity(0.15) : Color.clear)
)
.contentShape(Rectangle())
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 12) {
ForEach(AppTheme.allCases) { theme in
Button {
appThemeRawValue = theme.rawValue
} label: {
Text(theme.displayNameKey)
.bitchatFont(size: 13, weight: selectedTheme == theme ? .semibold : .regular)
.foregroundColor(selectedTheme == theme ? palette.accent : secondaryTextColor)
.padding(.horizontal, 10)
.padding(.vertical, 6)
.background(
RoundedRectangle(cornerRadius: 8, style: .continuous)
.fill(selectedTheme == theme ? palette.accent.opacity(0.15) : Color.clear)
)
.contentShape(Rectangle())
}
.buttonStyle(.plain)
.accessibilityAddTraits(selectedTheme == theme ? .isSelected : [])
}
}
.buttonStyle(.plain)
.accessibilityAddTraits(selectedTheme == theme ? .isSelected : [])
}
}