Skip to content

A full-powered SwiftUI menu-bar app that overcomes MenuBarExtra’s limitations through the elegant integration of AppKit. Features right-click support, detachable panels, programmatic key window management, and Sparkle 2.0 updates.

License

Notifications You must be signed in to change notification settings

JPToroDev/FontSwitch

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Font Switch app icon

Font Switch

A full-powered menu-bar app that beautifully blends SwiftUI and AppKit

Swift 6.0 macOS 15.0+ MIT License

FeaturesInstallationArchitectureResources


🛠️ Overview

Font Switch is a full-powered menu-bar application that pushes SwiftUI to its limits and uses AppKit to reach the finish line. While MenuBarExtra works great for simple cases, it doesn't handle right-click detection or draggable windows. SwiftUI's new window-management APIs are powerful, but not quite complete—for example, there's no way to programmatically set the key (focused) window.

Font Switch showcases how to build a production-ready menu-bar application using Swift 6 and the latest and greatest from SwiftUI—including the @Observable macro, window APIs, and onKeyPress() modifier. It also demonstrates Sparkle 2.0 integration for App Store alternatives and global shortcuts via HotKey. And that's just the tip of the iceberg.

✨ Features

Core Functionality

  • 🎯 Global Font Switching — Instantly change the font of text selected in any application
  • 📚 Full-Fledged Font Manager — CRUD operations for fonts and font collections
  • 👁️ Font Visibility Control — Hide unwanted fonts to declutter your font picker
  • ⌨️ Keyboard Navigation — Full keyboard support with focus rings and arrow key navigation

Developer Highlights

  • Modern Architectures — Swift 6, structured concurrency, and the @Observable macro
  • SwiftUI + AppKit Integration — Full-powered menu-bar app using NSStatusItem, NSPanel, and @NSApplicationDelegateAdaptor
  • Keyboard Shortcuts Galore — Global shortcuts via HotKey and view-specific commands via onKeyPress()
  • Custom Environment ActionsDismissAction-style custom environment types
  • Sparkle Integration — Complete app update system with beta channel support via Sparkle

📸 Screenshots

Floating font-picker panel with programmatic focus (key state)
Floating font-picker panel with programmatic focus (key state)

Font manager with collection browser and font visibility controls
Font manager with collection browser and font visibility controls

Settings and right-click menu
Settings and menu-bar right-click menu

🚀 Installation

Requirements

  • macOS 15.0 or later
  • Xcode 26.0 or later
  • Swift 6.0 or later

Building from Source

Before building, set:

  1. DEVELOPMENT_TEAM — your Apple Team ID
  2. BUNDLE_ID_PREFIX — your reverse-domain prefix (e.g. com.example)

Open the project in Xcode 26 or later and run on "My Mac".

Sparkle Setup

To set up Sparkle, check out Matteo Spada's exceptional implementation guide.

🏗 Architecture

Here's how Font Switch tackles some interesting macOS development challenges:

🍎 Menu Bar App with NSStatusItem

Since MenuBarExtra has limitations, Font Switch uses NSStatusItem for the menu bar integration:

  • Full control over right-click detection and context menus
  • NSHostingMenu to power AppKit menus with SwiftUI views—handy for avoiding runtime warnings when opening settings outside of a View

🪟 Floating Panels with NSPanel

The floating font picker uses a custom NSPanel implementation where standard window APIs fall short:

  • FocusablePanel subclass handles proper focus management and position persistence across app launches
  • Control whether the panel receives keyboard input (for searching) or the app with selected text receives input (for applying fonts) via the @Environment

🎨 Custom Environment Actions

Font Switch implements custom environment actions that work like DismissAction:

@Environment(\.focusMainWindow) private var focusMainWindow

Button("Focus Window") {
  focusMainWindow()
}

🔤 NSFontManager Integration

Font collection management uses NSFontManager for the heavy lifting:

  • Create, rename, and delete collections
  • Add fonts via context menu or drag-and-drop using the Transferable protocol
  • Font visibility control with UserDefaults persistence
  • Rich text formatting preservation when switching fonts across applications

⌨️ Advanced Keyboard Navigation

Keyboard navigation combines multiple techniques:

  • onKeyPress() for view-specific commands
  • @FocusState for managing focus across the interface
  • Custom focus rings that match each view's shape for a polished feel

📋 Pasteboard Integration

The font switching works by manipulating the pasteboard:

  • RTF formatting preservation
  • Programmatic copy/paste with CGEvent simulation
  • Original pasteboard state restoration after operations

📚 Resources

📄 License

Font Switch is available under the MIT License. See LICENSE file for details.

🙏 Acknowledgments

  • HotKey — Global shortcut framework
  • Sparkle — App update framework
  • App icon by Rudra Das

About

A full-powered SwiftUI menu-bar app that overcomes MenuBarExtra’s limitations through the elegant integration of AppKit. Features right-click support, detachable panels, programmatic key window management, and Sparkle 2.0 updates.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages