diff --git a/README.md b/README.md index 425aa2f..0457f58 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ This is not full Raycast parity: calendar/date/time-zone calculations, design un Select an application and open **Actions ⌘K**. **Open** is the first, default-selected action and uses the same launch path, successful-launch history tracking, dismissal, and error reporting as Return in the application list. Filtering resets selection to the first matching action; an empty result does nothing on Return. Up/Down or Control-K/Control-J navigates actions without changing the selected application. -- **Favorite / Remove Favorite** toggles the selected application's persisted favorite status, updates ranking immediately, and preserves the selection without recording a launch. Open remains the default action. Reset ranking clears usage but does not remove a favorite. +- **Favorite / Remove Favorite** toggles the selected application's persisted favorite status, updates ranking immediately, and preserves the selection without recording a launch. Favorited results show a filled star immediately to the left of the **Application** label. Open remains the default action. Reset ranking clears usage but does not remove a favorite. - **Show in Finder** reveals the selected application bundle and dismisses the launcher without restoring the previous application's focus. Its icon is the native monochrome Finder glyph; macOS versions without that symbol use Finder's application icon. - **Reset ranking** clears only the selected bundle's launch count and last-launch timestamp, including persisted history. Results reorder immediately while retaining the selected application; other copies and applications keep their history. Future launches start counting again. - **Quit application** sends a normal macOS quit request to running instances of that exact bundle, not another copy with the same name or bundle identifier. A non-running application is a no-op. The launcher dismisses after an accepted request; the application may still present save prompts or cancel quitting. Rejected requests show a native alert. Conjure never force-quits the application. diff --git a/Sources/Conjure/LauncherWindowController.swift b/Sources/Conjure/LauncherWindowController.swift index cf9ba5a..65c73d4 100644 --- a/Sources/Conjure/LauncherWindowController.swift +++ b/Sources/Conjure/LauncherWindowController.swift @@ -533,6 +533,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe ?? makeCell(identifier: identifier) if let calculation { cell.textField?.stringValue = calculation.displayValue + cell.textField?.setAccessibilityLabel(nil) cell.locationLabel.isHidden = true cell.kindLabel.stringValue = isCurrencyCalculation ? "Daily rates" : calculation.copyValue == nil ? "Error" : "Calculator" @@ -546,7 +547,10 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe let location = locationLabels[application.id] cell.locationLabel.stringValue = location ?? "" cell.locationLabel.isHidden = location == nil - cell.kindLabel.stringValue = "Application" + let isFavorite = history.isFavorite(application) + cell.kindLabel.attributedStringValue = isFavorite + ? ApplicationCell.favoriteKind : ApplicationCell.applicationKind + cell.textField?.setAccessibilityLabel(isFavorite ? "\(application.name), Favorite" : nil) cell.imageView?.contentTintColor = nil cell.imageView?.image = NSWorkspace.shared.icon(forFile: application.url.path) cell.toolTip = application.url.path @@ -729,6 +733,22 @@ final class ApplicationCell: NSTableCellView { private static let opaqueMask = [NSColor.black.cgColor, NSColor.black.cgColor] private static let fadedMask = [NSColor.black.cgColor, NSColor.clear.cgColor] private static let timing = CAMediaTimingFunction(name: .easeOut) + static let applicationKind = NSAttributedString(string: "Application", attributes: [ + .font: NSFont.systemFont(ofSize: 14), .foregroundColor: SunsetPalette.secondaryText + ]) + static let favoriteKind: NSAttributedString = { + let attachment = NSTextAttachment() + attachment.image = NSImage(systemSymbolName: "star.fill", accessibilityDescription: "Favorite")? + .withSymbolConfiguration(NSImage.SymbolConfiguration(pointSize: 12, weight: .regular) + .applying(.init(paletteColors: [SunsetPalette.secondaryText]))) + let size = attachment.image?.size ?? .zero + attachment.bounds = NSRect(x: 0, y: (NSFont.systemFont(ofSize: 14).capHeight - size.height) / 2, + width: size.width, height: size.height) + let title = NSMutableAttributedString(attachment: attachment) + title.append(NSAttributedString(string: " ")) + title.append(applicationKind) + return title + }() let locationLabel = NSTextField(labelWithString: "") let kindLabel = NSTextField(labelWithString: "Application") diff --git a/TODO.md b/TODO.md index 8bee9a0..33ee8ab 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1,5 @@ - [x] Add Favorite / Remove Favorite actions and persist favorites by application bundle. - Empty search: favorites first, then usage ranking within each group. - - Typed search: match quality first, then favorites, launch count, recency, and alphabetical order. \ No newline at end of file + - Typed search: match quality first, then favorites, launch count, recency, and alphabetical order. +- [x] add a star icon to the left of the "Application" type text in the selection entries for favorited items +- [ ] add some spacing between the favorites grouping and the rest of the applications \ No newline at end of file