From 86632f1d860d4b9e942e50c135e96b11abeb640a Mon Sep 17 00:00:00 2001 From: hl-valdemar Date: Sun, 18 Oct 2026 00:22:36 +0200 Subject: [PATCH] fix: replace provider indicator with expanded picker --- README.md | 2 +- Sources/Conjure/ApplicationActionsController.swift | 4 ++-- Tests/ConjureKitTests/ActionsBackgroundTests.swift | 12 ++++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d222424..d81ba4b 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ Notes autosave locally as RTFD packages, including embedded images, under `~/Lib Search for **Conjure Translate**, identified by its centered 🌏 icon, and open it. Choose a provider in the pill-shaped header selector, enter text in the search bar, then press Return or click **Translate**. Typing alone never sends text. When the translation is available, the action changes to **Copy**: press Return or click it to copy the full translation and close Conjure. Command-C still copies selected output. Editing the input restores **Translate**. -The provider selector opens a searchable action-style popup below the header, with a checkmark beside the current provider. Use Up/Down and Return or click a provider to select it; Back or clicking outside closes the popup. Changing providers clears the previous result without submitting a request. +The provider selector expands into a searchable action-style popup from its top edge downwards, hiding the indicator until the popup closes. A checkmark marks the current provider. Use Up/Down and Return or click a provider to select it; Back or clicking outside closes the popup. Changing providers clears the previous result without submitting a request. The footer shows the current language pair (initially **English → Japanese**). Click it or open **Actions** with Command-K to change the source language, change the target language, or swap them. Language choices are saved locally and apply to both providers. Changing languages clears the previous result without submitting another request. The input hint and output accessibility label follow the selected pair. Back closes Actions first, then returns to the launcher and restores your search; Escape or Command-W dismisses the entire window. diff --git a/Sources/Conjure/ApplicationActionsController.swift b/Sources/Conjure/ApplicationActionsController.swift index cf8cb76..32f5a94 100644 --- a/Sources/Conjure/ApplicationActionsController.swift +++ b/Sources/Conjure/ApplicationActionsController.swift @@ -207,10 +207,10 @@ final class ApplicationActionsController: NSViewController, NSSearchFieldDelegat NSLayoutConstraint.activate([ view.trailingAnchor.constraint(equalTo: pill.trailingAnchor), belowAnchor - ? view.topAnchor.constraint(equalTo: pill.bottomAnchor, constant: 8) + ? view.topAnchor.constraint(equalTo: pill.topAnchor) : view.bottomAnchor.constraint(equalTo: pill.bottomAnchor) ]) - coveredPill = belowAnchor ? nil : pill + coveredPill = pill coveredPillAlpha = pill.alphaValue } coveredPill?.setAccessibilityHidden(true) diff --git a/Tests/ConjureKitTests/ActionsBackgroundTests.swift b/Tests/ConjureKitTests/ActionsBackgroundTests.swift index d9d84f2..c0920aa 100644 --- a/Tests/ConjureKitTests/ActionsBackgroundTests.swift +++ b/Tests/ConjureKitTests/ActionsBackgroundTests.swift @@ -30,7 +30,7 @@ import Testing } } -@Test @MainActor func providerPickerOpensBelowAnchorAndKeepsCurrentSelection() throws { +@Test @MainActor func providerPickerReplacesAnchorDownwardAndKeepsCurrentSelection() throws { _ = NSApplication.shared let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 750, height: 480), styleMask: .borderless, backing: .buffered, defer: false) @@ -47,17 +47,21 @@ import Testing popup.showProviders(selectedOpenAI: true, relativeTo: anchor) host.layoutSubtreeIfNeeded() let rect = popup.view.convert(popup.view.bounds, to: host) - #expect(rect.maxY < pill.frame.minY) + #expect(rect.maxY == pill.frame.maxY) + #expect(rect.minY < pill.frame.minY) #expect(rect.maxX == pill.frame.maxX) - #expect(pill.alphaValue == 1) + #expect(pill.isAccessibilityHidden()) _ = popup.handle(#selector(NSResponder.insertNewline(_:))) #expect(selections == [true]) // Reopen during the close animation, then switch modes without retaining the old anchor. popup.showTranslation(relativeTo: anchor) popup.showProviders(selectedOpenAI: false, relativeTo: anchor) host.layoutSubtreeIfNeeded() - #expect(popup.view.convert(popup.view.bounds, to: host).maxY < pill.frame.minY) + #expect(popup.view.convert(popup.view.bounds, to: host).maxY == pill.frame.maxY) popup.moveSelection(by: 1) _ = popup.handle(#selector(NSResponder.insertNewline(_:))) #expect(selections == [true, true]) + popup.close(animated: false) + #expect(pill.alphaValue == 1) + #expect(!pill.isAccessibilityHidden()) }