diff --git a/README.md b/README.md index c09e162..f376874 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ The picker works offline with 1,870 emoji from [gemoji v4.1.0](https://github.co ## Notes -Search for **Conjure Notes**, or assign it a global shortcut in Settings. **New Note** (Command-N) creates a note; the menu switches between notes, and reopening Notes restores the last selection. Each note’s first nonempty line becomes its menu title. +Search for **Conjure Notes**, identified by its centered 📔 icon, or assign it a global shortcut in Settings. **New Note** (Command-N) creates a note; the menu switches between notes, and reopening Notes restores the last selection. Each note’s first nonempty line becomes its menu title. Edit Markdown directly: headings, bold, italic, lists, links, inline code, and fenced code blocks are highlighted while the source remains visible. Paste images or use **Insert Image…** to embed a local image. Command-Z undoes edits; Command-Shift-Z redoes them. Undo history is cleared when switching notes so edits cannot spill into another note. @@ -130,7 +130,7 @@ Notes autosave locally as RTFD packages, including embedded images, under `~/Lib ## Translation -Search for **Conjure Translate** and open it. Enter English in the search bar, choose a provider, then press Return or click **Translate**. Typing alone never sends text. Copy selected Japanese output with Command-C; the copy hint appears beside the Translate action at the bottom. The Back chevron beside the input returns to the launcher and restores your search; Escape dismisses Conjure. +Search for **Conjure Translate**, identified by its centered 🌏 icon, and open it. Enter English in the search bar, choose a provider, then press Return or click **Translate**. Typing alone never sends text. Copy selected Japanese output with Command-C; the copy hint appears beside the Translate action at the bottom. The Back chevron beside the input returns to the launcher and restores your search; Escape dismisses Conjure. Editing the input, switching providers, forgetting the key, or leaving Translate cancels the active request; cancelled results are not shown. After a request fails, submit again to retry. diff --git a/Sources/Conjure/LauncherWindowController.swift b/Sources/Conjure/LauncherWindowController.swift index e8d2beb..e6d8bfe 100644 --- a/Sources/Conjure/LauncherWindowController.swift +++ b/Sources/Conjure/LauncherWindowController.swift @@ -40,8 +40,12 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe private var isCommandOpen: Bool { activeCommand != nil } private var activeCommand: Application.Command? private var pendingPresentation: (() -> Void)? - private static let emojiIcon: NSImage = { - let text = NSAttributedString(string: "🤔", attributes: [.font: NSFont.systemFont(ofSize: 28)]) + private static let emojiIcon = makeEmojiIcon("🤔") + private static let notesIcon = makeEmojiIcon("📔") + private static let translateIcon = makeEmojiIcon("🌏") + + private static func makeEmojiIcon(_ emoji: String) -> NSImage { + let text = NSAttributedString(string: emoji, attributes: [.font: NSFont.systemFont(ofSize: 28)]) let line = CTLineCreateWithAttributedString(text) return NSImage(size: NSSize(width: 32, height: 32), flipped: false) { rect in guard let context = NSGraphicsContext.current?.cgContext else { return false } @@ -51,7 +55,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe CTLineDraw(line, context) return true } - }() + } init(history: LaunchHistory = LaunchHistory(), uninstaller: ApplicationUninstaller = ApplicationUninstaller(), defaults: UserDefaults = .standard, pasteboard: NSPasteboard = .general, notesDirectory: URL? = nil) { @@ -577,13 +581,13 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe cell.imageView?.image = Self.emojiIcon cell.toolTip = "Search and copy emoji" case .notes: - cell.imageView?.image = NSImage(systemSymbolName: "note.text", accessibilityDescription: nil) + cell.imageView?.image = Self.notesIcon cell.toolTip = "Write notes with Markdown and images" default: - cell.imageView?.image = NSImage(systemSymbolName: "character.bubble", accessibilityDescription: nil) + cell.imageView?.image = Self.translateIcon cell.toolTip = "Translate English to Japanese" } - cell.imageView?.contentTintColor = entry.command == .emoji ? nil : SunsetPalette.accent + cell.imageView?.contentTintColor = nil } else { let application = results[row] cell.textField?.stringValue = application.name diff --git a/Tests/ConjureKitTests/EmojiIconTests.swift b/Tests/ConjureKitTests/EmojiIconTests.swift index aa616e1..f95a6b7 100644 --- a/Tests/ConjureKitTests/EmojiIconTests.swift +++ b/Tests/ConjureKitTests/EmojiIconTests.swift @@ -2,13 +2,14 @@ import AppKit import Testing @testable import Conjure -@Test @MainActor func emojiCommandArtworkHasBalancedVisiblePadding() throws { +@Test(arguments: ["emoji", "notes", "translate"]) +@MainActor func commandArtworkHasBalancedVisiblePadding(query: String) throws { _ = NSApplication.shared let launcher = LauncherWindowController() func descendants(_ view: NSView) -> [NSView] { [view] + view.subviews.flatMap(descendants) } let views = descendants(try #require(launcher.window?.contentView)) let search = try #require(views.compactMap { $0 as? NSSearchField }.first) - search.stringValue = "emoji" + search.stringValue = query launcher.controlTextDidChange(Notification(name: NSControl.textDidChangeNotification, object: search)) let table = try #require(views.compactMap { $0 as? NSTableView }.first) let cell = try #require(launcher.tableView(table, viewFor: nil, row: 0) as? ApplicationCell)