Skip to content

Commit df23476

Browse files
lividclaude
andcommitted
Adapt toolbar button colors for dark theme-color on pre-macOS 26
When the article's theme-color is dark, toolbar buttons become invisible against the dark background on pre-macOS 26 (macOS 26 handles this via liquid glass). Apply .environment(\.colorScheme, .dark) to toolbar item groups so buttons use proper system dark mode styling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0b9e9eb commit df23476

3 files changed

Lines changed: 113 additions & 79 deletions

File tree

Planet/Helper/ThemeColorExtractor.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@ struct ThemeColorExtractor {
101101
return NSColor(srgbRed: r, green: g, blue: b, alpha: 1.0)
102102
}
103103

104+
/// Returns true if the color's perceived luminance is dark.
105+
static func isDark(_ color: NSColor) -> Bool {
106+
guard let c = color.usingColorSpace(.sRGB) else { return false }
107+
let luminance = 0.299 * c.redComponent + 0.587 * c.greenComponent + 0.114 * c.blueComponent
108+
return luminance < 0.5
109+
}
110+
104111
// MARK: - Private Helpers
105112

106113
private static func readHead(of url: URL, maxBytes: Int) -> Data? {

Planet/Views/Articles/ArticleView.swift

Lines changed: 105 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -307,113 +307,122 @@ struct ArticleView: View {
307307
.toolbar {
308308
ToolbarItemGroup(placement: .automatic) {
309309
// Functions for the current selected planet
310-
toolbarPlanetView()
311-
toolbarArticlePlanetAvatarView()
310+
Group {
311+
toolbarPlanetView()
312+
toolbarArticlePlanetAvatarView()
313+
}
314+
.darkThemeToolbarStyle(isDarkThemeColor)
312315
}
313316

314317
ToolbarItemGroup(placement: .automatic) {
315318
Spacer()
316-
if let article = planetStore.selectedArticle {
317-
Menu {
318-
ArticleSetStarView(article: article)
319-
} label: {
320-
ArticleToolbarStarView(article: article)
319+
Group {
320+
if let article = planetStore.selectedArticle {
321+
Menu {
322+
ArticleSetStarView(article: article)
323+
} label: {
324+
ArticleToolbarStarView(article: article)
325+
}
321326
}
322-
}
323-
324-
if let article = planetStore.selectedArticle,
325-
article.hasAudio
326-
{
327-
toolbarAudioView(article: article)
328-
}
329327

330-
// Menu for accessing the attachments if any
331-
if let article = planetStore.selectedArticle, let attachments = article.attachments,
332-
attachments.count > 0
333-
{
334-
toolbarAttachmentsView(article: article)
335-
}
328+
if let article = planetStore.selectedArticle,
329+
article.hasAudio
330+
{
331+
toolbarAudioView(article: article)
332+
}
336333

337-
if (settingsAIIsReady || isOnDeviceAIAvailable), let article = planetStore.selectedArticle {
338-
Button {
339-
ArticleAIChatWindowManager.shared.open(for: article)
340-
} label: {
341-
HStack(spacing: 4) {
342-
Image(systemName: "sparkles")
343-
if aiChatResponseCount > 0 {
344-
Text("\(aiChatResponseCount)")
345-
.font(.caption)
346-
.foregroundStyle(.secondary)
347-
}
348-
}
334+
// Menu for accessing the attachments if any
335+
if let article = planetStore.selectedArticle, let attachments = article.attachments,
336+
attachments.count > 0
337+
{
338+
toolbarAttachmentsView(article: article)
349339
}
350-
.help("Chat with AI about this article")
351-
}
352340

353-
if let followingArticle = planetStore.selectedArticle as? FollowingArticleModel {
354-
if followingArticle.supportsReaderView {
341+
if (settingsAIIsReady || isOnDeviceAIAvailable), let article = planetStore.selectedArticle {
355342
Button {
356-
setReaderViewEnabled(!showLocalRendered, for: followingArticle.planet)
357-
syncSelectedArticlePresentation()
343+
ArticleAIChatWindowManager.shared.open(for: article)
358344
} label: {
359-
Image(systemName: showLocalRendered ? "globe" : "doc.richtext")
345+
HStack(spacing: 4) {
346+
Image(systemName: "sparkles")
347+
if aiChatResponseCount > 0 {
348+
Text("\(aiChatResponseCount)")
349+
.font(.caption)
350+
.foregroundStyle(.secondary)
351+
}
352+
}
360353
}
361-
.help(showLocalRendered ? "Show Original Website" : "Show Reader View")
354+
.help("Chat with AI about this article")
362355
}
363356

364-
if followingArticle.supportsReadAloud {
365-
Button {
366-
toggleSpeechPlayback(for: followingArticle)
367-
} label: {
368-
Image(systemName: speechPlayerViewModel.isSpeaking ? "speaker.wave.2.fill" : "speaker.wave.2")
357+
if let followingArticle = planetStore.selectedArticle as? FollowingArticleModel {
358+
if followingArticle.supportsReaderView {
359+
Button {
360+
setReaderViewEnabled(!showLocalRendered, for: followingArticle.planet)
361+
syncSelectedArticlePresentation()
362+
} label: {
363+
Image(systemName: showLocalRendered ? "globe" : "doc.richtext")
364+
}
365+
.help(showLocalRendered ? "Show Original Website" : "Show Reader View")
369366
}
370-
.disabled(detectedSpeechLanguage == nil)
371-
.help(speechPlaybackHelpText())
372-
}
373-
}
374367

375-
if let article = planetStore.selectedArticle as? MyArticleModel, !article.isAggregated() {
376-
Button {
377-
do {
378-
try WriterStore.shared.editArticle(for: article)
368+
if followingArticle.supportsReadAloud {
369+
Button {
370+
toggleSpeechPlayback(for: followingArticle)
371+
} label: {
372+
Image(systemName: speechPlayerViewModel.isSpeaking ? "speaker.wave.2.fill" : "speaker.wave.2")
373+
}
374+
.disabled(detectedSpeechLanguage == nil)
375+
.help(speechPlaybackHelpText())
379376
}
380-
catch {
381-
PlanetStore.shared.alert(title: "Failed to launch writer")
377+
}
378+
379+
if let article = planetStore.selectedArticle as? MyArticleModel, !article.isAggregated() {
380+
Button {
381+
do {
382+
try WriterStore.shared.editArticle(for: article)
383+
}
384+
catch {
385+
PlanetStore.shared.alert(title: "Failed to launch writer")
386+
}
387+
} label: {
388+
Image(systemName: "pencil.line")
382389
}
383-
} label: {
384-
Image(systemName: "pencil.line")
390+
.help("Edit Selected Article")
391+
.keyboardShortcut("e", modifiers: [.command])
385392
}
386-
.help("Edit Selected Article")
387-
.keyboardShortcut("e", modifiers: [.command])
388393
}
394+
.darkThemeToolbarStyle(isDarkThemeColor)
389395
}
390396

391397
ToolbarItemGroup(placement: .automatic) {
392398
Spacer()
393-
Button {
394-
planetStore.isShowingSearch = true
395-
} label: {
396-
Image(systemName: "magnifyingglass")
397-
}
398-
.help("Search")
399-
.keyboardShortcut("f", modifiers: [.command])
400-
401-
if let _ = planetStore.selectedArticle {
399+
Group {
402400
Button {
403-
isSharing = true
401+
planetStore.isShowingSearch = true
404402
} label: {
405-
Image(systemName: "square.and.arrow.up")
403+
Image(systemName: "magnifyingglass")
406404
}
407-
.background(
408-
SharingServicePicker(
409-
isPresented: $isSharing,
410-
sharingItems: [
411-
sharingItem ?? URL(string: "https://planetable.eth.limo")!
412-
]
405+
.help("Search")
406+
.keyboardShortcut("f", modifiers: [.command])
407+
408+
if let _ = planetStore.selectedArticle {
409+
Button {
410+
isSharing = true
411+
} label: {
412+
Image(systemName: "square.and.arrow.up")
413+
}
414+
.background(
415+
SharingServicePicker(
416+
isPresented: $isSharing,
417+
sharingItems: [
418+
sharingItem ?? URL(string: "https://planetable.eth.limo")!
419+
]
420+
)
413421
)
414-
)
415-
.help("Share Selected Article")
422+
.help("Share Selected Article")
423+
}
416424
}
425+
.darkThemeToolbarStyle(isDarkThemeColor)
417426
}
418427
}
419428
}
@@ -690,6 +699,11 @@ struct ArticleView: View {
690699
)
691700
}
692701

702+
private var isDarkThemeColor: Bool {
703+
guard let color = themeColor else { return false }
704+
return ThemeColorExtractor.isDark(color)
705+
}
706+
693707
private func reExtractThemeColor() {
694708
guard url.isFileURL else { return }
695709
themeColor = ThemeColorExtractor.extractColor(from: url)
@@ -1041,3 +1055,16 @@ struct ArticleView: View {
10411055
}
10421056
}
10431057
}
1058+
1059+
private extension View {
1060+
@ViewBuilder
1061+
func darkThemeToolbarStyle(_ isDark: Bool) -> some View {
1062+
if #available(macOS 26, *) {
1063+
self
1064+
} else if isDark {
1065+
self.environment(\.colorScheme, .dark)
1066+
} else {
1067+
self
1068+
}
1069+
}
1070+
}

Planet/versioning.xcconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
CURRENT_PROJECT_VERSION = 2797
1+
CURRENT_PROJECT_VERSION = 2798

0 commit comments

Comments
 (0)