diff --git a/Mac/About/AboutWindowController.swift b/Mac/About/AboutWindowController.swift
new file mode 100644
index 000000000..942ba327e
--- /dev/null
+++ b/Mac/About/AboutWindowController.swift
@@ -0,0 +1,80 @@
+//
+// AboutWindowController.swift
+// NetNewsWire
+//
+// Created by Stuart Breckenridge on 26/06/2025.
+// Copyright © 2025 Ranchero Software. All rights reserved.
+//
+
+import Cocoa
+
+class AboutWindowController: NSWindowController {
+
+ @IBOutlet weak var appIconImageView: NSImageView!
+ @IBOutlet weak var appTitleLabel: NSTextField!
+ @IBOutlet weak var versionLabel: NSTextField!
+ @IBOutlet weak var copyrightLabel: NSTextField!
+ @IBOutlet weak var websiteLabel: LinkLabel!
+ @IBOutlet weak var creditsTextView: NSTextView!
+
+ override func windowDidLoad() {
+ super.windowDidLoad()
+ configureWindow()
+ updateUI()
+ }
+
+ func configureWindow() {
+ window?.isOpaque = false
+ window?.backgroundColor = .clear
+ window?.titlebarAppearsTransparent = true
+ window?.titleVisibility = .hidden
+ window?.styleMask.insert(.fullSizeContentView)
+ if let contentView = window?.contentView {
+ let visualEffectView = NSVisualEffectView(frame: contentView.bounds)
+ visualEffectView.autoresizingMask = [.width, .height]
+ visualEffectView.blendingMode = .behindWindow
+ visualEffectView.material = .titlebar
+ visualEffectView.state = .active
+ contentView.addSubview(visualEffectView, positioned: .below, relativeTo: nil)
+ }
+ }
+
+ private func updateUI() {
+
+ // App Icon
+ appIconImageView.image = NSApp.applicationIconImage
+
+ // Version
+ let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
+ let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "Unknown"
+ let versionString = "Version \(version) (Build \(build))"
+ versionLabel.stringValue = versionString
+
+ // Copyright
+ let copyright = Bundle.main.infoDictionary?["NSHumanReadableCopyright"] as? String ?? "Copyright © 2002-2025 Brent Simmons. All rights reserved."
+ copyrightLabel.stringValue = copyright
+
+ // Credits
+ if let creditsURL = Bundle.main.url(forResource: "Credits", withExtension: "rtf"),
+ let creditsData = try? Data(contentsOf: creditsURL),
+ let attributedString = try? NSAttributedString(data: creditsData, options: [.documentType: NSAttributedString.DocumentType.rtf], documentAttributes: nil) {
+ creditsTextView.textStorage?.setAttributedString(attributedString)
+ } else {
+ creditsTextView.string = "Credits not available."
+ }
+
+ let fullRange = NSRange(location: 0, length: creditsTextView.string.utf16.count)
+ let leadingParagraphStyle = NSMutableParagraphStyle()
+ leadingParagraphStyle.alignment = .left
+ creditsTextView.textStorage?.addAttribute(.paragraphStyle, value: leadingParagraphStyle, range: fullRange)
+
+ // URL
+ let url = URL(string: "https://inessential.com")!
+ let attributedString = NSMutableAttributedString(string: "inessential.com")
+ attributedString.addAttribute(.link, value: url, range: NSRange(location: 0, length: attributedString.length))
+ attributedString.addAttribute(.foregroundColor, value: NSColor.systemBlue, range: NSRange(location: 0, length: attributedString.length))
+ attributedString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: attributedString.length))
+ websiteLabel.attributedStringValue = attributedString
+ }
+
+}
diff --git a/Mac/About/AboutWindowController.xib b/Mac/About/AboutWindowController.xib
new file mode 100644
index 000000000..52857ec84
--- /dev/null
+++ b/Mac/About/AboutWindowController.xib
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Mac/About/LinkLabel.swift b/Mac/About/LinkLabel.swift
new file mode 100644
index 000000000..4f298175b
--- /dev/null
+++ b/Mac/About/LinkLabel.swift
@@ -0,0 +1,16 @@
+//
+// LinkLabel.swift
+// NetNewsWire
+//
+// Created by Stuart Breckenridge on 26/06/2025.
+// Copyright © 2025 Ranchero Software. All rights reserved.
+//
+
+
+class LinkLabel: NSTextField {
+
+ /// pièces de résistance -- keeping it a mac-assed mac app.
+ override func resetCursorRects() {
+ addCursorRect(bounds, cursor: .pointingHand)
+ }
+}
diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift
index adf91c8a5..1ff0799a5 100644
--- a/Mac/AppDelegate.swift
+++ b/Mac/AppDelegate.swift
@@ -277,7 +277,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
CrashReporter.check(crashReporter: self.crashReporter)
}
#endif
-
}
func application(_ application: NSApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([NSUserActivityRestoring]) -> Void) -> Bool {
@@ -675,6 +674,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
createAndShowMainWindowIfNecessary()
mainWindowController!.gotoStarred(sender)
}
+
+ @IBAction func showCustomAboutPanel(_ sender: Any?) {
+ let aboutWC = AboutWindowController(windowNibName: "AboutWindowController")
+ aboutWC.showWindow(nil)
+ aboutWC.window?.center()
+ aboutWC.window?.makeKeyAndOrderFront(nil)
+ }
@IBAction func sortByOldestArticleOnTop(_ sender: Any?) {
diff --git a/Mac/Base.lproj/Main.storyboard b/Mac/Base.lproj/Main.storyboard
index c2906ddec..536c5fe1c 100644
--- a/Mac/Base.lproj/Main.storyboard
+++ b/Mac/Base.lproj/Main.storyboard
@@ -1,8 +1,7 @@
-
+
-
-
+
@@ -18,7 +17,7 @@
diff --git a/Mac/Resources/Credits.rtf b/Mac/Resources/Credits.rtf
index ce67ed372..1291f7c3a 100644
--- a/Mac/Resources/Credits.rtf
+++ b/Mac/Resources/Credits.rtf
@@ -1,52 +1,64 @@
-{\rtf1\ansi\ansicpg1252\cocoartf2761
-\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 LucidaGrande-Bold;\f1\fnil\fcharset0 LucidaGrande;}
+{\rtf1\ansi\ansicpg1252\cocoartf2859
+\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 SFPro-Bold;\f1\fnil\fcharset0 SFPro-Regular;}
{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
{\*\expandedcolortbl;;\cssrgb\c0\c0\c0\cname textColor;}
\vieww14060\viewh15660\viewkind0
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl360\slmult1\pardirnatural\partightenfactor0
-{\field{\*\fldinst{HYPERLINK "https://ranchero.com/netnewswire/"}}{\fldrslt
-\f0\b\fs22 \cf2 NetNewsWire}}
-\f0\b\fs22 \cf2 \
-By Brent Simmons\
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl360\slmult1\pardirnatural\partightenfactor0
-{\field{\*\fldinst{HYPERLINK "http://inessential.com/"}}{\fldrslt \cf2 inessential.com}}
+\deftab720
+\pard\pardeftab720\sa60\partightenfactor0
+
+\f0\b\fs22 \cf2 Credits
\f1\b0 \
+\pard\pardeftab720\sl144\slmult1\sa60\partightenfactor0
+\cf2 \
+\pard\pardeftab720\sl168\slmult1\sa60\partightenfactor0
+\cf2 Contributing Developers \
+{\field{\*\fldinst{HYPERLINK "https://github.com/vincode-io"}}{\fldrslt Maurice Parker}}, {\field{\*\fldinst{HYPERLINK "https://stuartbreckenridge.net/"}}{\fldrslt Stuart Breckenridge}}\
+\
+App Icon\
+{\field{\*\fldinst{HYPERLINK "https://twitter.com/BradEllis"}}{\fldrslt Brad Ellis}}\
+\
+Feedly Syncing\
+{\field{\*\fldinst{HYPERLINK "https://twitter.com/kielgillard"}}{\fldrslt Kiel Gillard}}\
+\
+NewsBlur Syncing\
+{\field{\*\fldinst{HYPERLINK "https://twitter.com/quanganhdo"}}{\fldrslt Anh Do}}\
+\
+Under-the-Hood Magic and CSS Stylin's\
+{\field{\*\fldinst{HYPERLINK "https://github.com/wevah"}}{\fldrslt Nate Weaver}}\
+\
+Newsfoot (JS footnote displayer)\
+{\field{\*\fldinst{HYPERLINK "https://github.com/brehaut/"}}{\fldrslt Andrew Brehaut}}\
+\
+Help Book\
+{\field{\*\fldinst{HYPERLINK "https://nostodnayr.net/"}}{\fldrslt Ryan Dotson}}\
+\
+And featuring contributions from\
+{\field{\*\fldinst{HYPERLINK "https://github.com/danielpunkass"}}{\fldrslt Daniel Jalkut}}, {\field{\*\fldinst{HYPERLINK "https://rhonabwy.com/"}}{\fldrslt Joe Heck}}, {\field{\*\fldinst{HYPERLINK "https://github.com/olofhellman"}}{\fldrslt Olof Hellman}}, {\field{\*\fldinst{HYPERLINK "https://blog.rizwan.dev/"}}{\fldrslt Rizwan Mohamed Ibrahim}}, {\field{\*\fldinst{HYPERLINK "https://twitter.com/philviso"}}{\fldrslt Phil Viso}}, and {\field{\*\fldinst{HYPERLINK "https://github.com/Ranchero-Software/NetNewsWire/graphs/contributors"}}{\fldrslt many more}}!\
\pard\pardeftab720\li360\sa60\partightenfactor0
\cf2 \
\pard\pardeftab720\sa60\partightenfactor0
-\f0\b \cf2 Credits:
-\f1\b0 \
-\pard\pardeftab720\li360\sa60\partightenfactor0
-\cf2 Contributing developers: {\field{\*\fldinst{HYPERLINK "https://github.com/vincode-io"}}{\fldrslt Maurice Parker}}, {\field{\*\fldinst{HYPERLINK "https://stuartbreckenridge.net/"}}{\fldrslt Stuart Breckenridge}}\
-App icon: {\field{\*\fldinst{HYPERLINK "https://twitter.com/BradEllis"}}{\fldrslt Brad Ellis}}\
-Feedly syncing: {\field{\*\fldinst{HYPERLINK "https://twitter.com/kielgillard"}}{\fldrslt Kiel Gillard}}\
-NewsBlur syncing: {\field{\*\fldinst{HYPERLINK "https://twitter.com/quanganhdo"}}{\fldrslt Anh Do}}\
-Under-the-hood magic and CSS stylin\'92s: {\field{\*\fldinst{HYPERLINK "https://github.com/wevah"}}{\fldrslt Nate Weaver}}\
-Newsfoot (JS footnote displayer): {\field{\*\fldinst{HYPERLINK "https://github.com/brehaut/"}}{\fldrslt Andrew Brehaut}}\
-Help book: {\field{\*\fldinst{HYPERLINK "https://nostodnayr.net/"}}{\fldrslt Ryan Dotson}}\
-And featuring contributions from {\field{\*\fldinst{HYPERLINK "https://github.com/danielpunkass"}}{\fldrslt Daniel Jalkut}}, {\field{\*\fldinst{HYPERLINK "https://rhonabwy.com/"}}{\fldrslt Joe Heck}}, {\field{\*\fldinst{HYPERLINK "https://github.com/olofhellman"}}{\fldrslt Olof Hellman}}, {\field{\*\fldinst{HYPERLINK "https://blog.rizwan.dev/"}}{\fldrslt Rizwan Mohamed Ibrahim}}, {\field{\*\fldinst{HYPERLINK "https://twitter.com/philviso"}}{\fldrslt Phil Viso}}, and {\field{\*\fldinst{HYPERLINK "https://github.com/Ranchero-Software/NetNewsWire/graphs/contributors"}}{\fldrslt many more}}!\
-\
-\pard\pardeftab720\sa60\partightenfactor0
+\f0\b \cf2 Acknowledgments\
-\f0\b \cf2 Acknowledgments:
\f1\b0 \
-\pard\pardeftab720\li360\sa60\partightenfactor0
+\pard\pardeftab720\sl168\slmult1\sa60\partightenfactor0
{\field{\*\fldinst{HYPERLINK "https://github.com/ccgus/fmdb"}}{\fldrslt \cf2 FMDB}} (greatest SQLite wrapper ever in history) is by {\field{\*\fldinst{HYPERLINK "http://flyingmeat.com/"}}{\fldrslt Flying Meat Software}}.\
-\pard\pardeftab720\li360\sa60\partightenfactor0
-{\field{\*\fldinst{HYPERLINK "https://sparkle-project.org/"}}{\fldrslt \cf2 Sparkle}} is by Sparkle Project.\
\
+{\field{\*\fldinst{HYPERLINK "https://sparkle-project.org/"}}{\fldrslt Sparkle}} is by Sparkle Project.\
+\pard\pardeftab720\li360\sa60\partightenfactor0
+\cf2 \
\pard\pardeftab720\sa60\partightenfactor0
-\f0\b \cf2 Thanks:\
-\pard\pardeftab720\li360\sa60\partightenfactor0
-
-\f1\b0 \cf2 Thanks to Sheila and my family; thanks to my friends in Seattle and around the globe; thanks to the ever-patient and ever-awesome NetNewsWire beta testers. Thanks to {\field{\*\fldinst{HYPERLINK "https://github.com/"}}{\fldrslt GitHub}} and {\field{\*\fldinst{HYPERLINK "https://slack.com/"}}{\fldrslt Slack}} for making open source collaboration easy and fun.\
+\f0\b \cf2 Thanks\
\
+
+\f1\b0 Thanks to Sheila and my family; thanks to my friends in Seattle and around the globe; thanks to the ever-patient and ever-awesome NetNewsWire beta testers. Thanks to {\field{\*\fldinst{HYPERLINK "https://github.com/"}}{\fldrslt GitHub}} and {\field{\*\fldinst{HYPERLINK "https://slack.com/"}}{\fldrslt Slack}} for making open source collaboration easy and fun.\
+\pard\pardeftab720\li360\sa60\partightenfactor0
+\cf2 \
\pard\pardeftab720\sa60\partightenfactor0
-\f0\b \cf2 Dedication:\
-\pard\pardeftab720\li360\sa60\partightenfactor0
+\f0\b \cf2 Dedication\
+\
-\f1\b0 \cf2 NetNewsWire 6 is dedicated to everyone working to save democracy around the world.\
+\f1\b0 NetNewsWire 6 is dedicated to everyone working to save democracy around the world.\
}
\ No newline at end of file