-
Notifications
You must be signed in to change notification settings - Fork 0
Closed as not planned
Description
Add a standalone floating contextual menu that can appear even when the keyboard overlay is not shown.
Problem
The Overlay Context Integration (previous ticket) works great for users who have the keyboard overlay visible. However, some users:
- Don't use the overlay (prefer cleaner screen)
- Have overlay hidden/dimmed
- Want contextual help without full keyboard display
This ticket adds a lightweight floating menu as an alternative.
User Workflow
When overlay is hidden:
-
User presses Leader → w
-
Floating menu appears near cursor or screen center:
┌────────────────────────────────┐ │ Window Management (Press key) │ ├────────────────────────────────┤ │ [H] Left Half │ │ [L] Right Half │ │ [K] Maximize │ │ [J] Center │ │ [Y] Top-Left [U] Top-Right │ │ [B] Bottom-Left [N] Bottom-Rgt │ │ [M] Next Display [Z] Undo │ └────────────────────────────────┘ -
User presses H → menu dismisses, window snaps
-
OR: 5s timeout → menu auto-dismisses
-
OR: Esc → menu dismisses
When overlay is visible:
- Use overlay context integration (previous ticket)
- Don't show standalone menu (avoid redundancy)
Implementation
ContextMenuWindow.swift (new, ~200 lines)
Features:
- Floating NSPanel window (non-activating)
- Positioned near cursor or screen center
- Compact layout showing only active keys
- Same data model as overlay version
- Smooth fade in/out animations
- Auto-dismiss on action or timeout
Architecture:
@MainActor
final class ContextMenuWindow: NSPanel {
private var contextLayer: String?
private var mappings: [KeyMapping] = []
private var dismissTimer: Timer?
func show(for layer: String, with mappings: [KeyMapping]) {
// Position near cursor
// Fade in animation
// Start dismiss timer
}
func dismiss() {
// Fade out animation
// Close window
}
}ContextMenuContentView.swift (new, ~100 lines)
SwiftUI view for menu content:
struct ContextMenuContentView: View {
let layerName: String
let mappings: [KeyMapping]
var body: some View {
VStack(spacing: 8) {
// Header
Text(layerName)
// Key grid (compact layout)
LazyVGrid(columns: 2) {
ForEach(mappings) { mapping in
KeyActionRow(
key: mapping.input,
action: mapping.actionLabel
)
}
}
}
}
}Integration Points
RuntimeCoordinator.swift (+30 lines):
- Check if overlay is visible
- If not, show standalone menu
- If yes, use overlay context (existing)
Settings (+20 lines):
enableStandaloneContextMenu: BoolcontextMenuTimeout: TimeInterval- Preference to choose overlay vs standalone
Visual Design
Compact, focused layout:
- Only shows mapped keys (not full keyboard)
- 2-column grid for efficiency
- Minimal chrome (just header + content)
- Semi-transparent background
- Drop shadow for depth
Positioning:
- Option 1: Near cursor (follows mouse)
- Option 2: Screen center (consistent location)
- Option 3: User-configurable position
Benefits
For users without overlay:
- Still get contextual help
- Lighter weight than full keyboard
- Cleaner screen real estate
For users with overlay:
- Choice of which to use
- Can disable standalone if redundant
- Preference for different contexts
Configuration
struct ContextMenuSettings {
var enableOverlayContext: Bool = true
var enableStandaloneMenu: Bool = false // Default OFF (overlay preferred)
var standalonePosition: MenuPosition = .nearCursor
var contextTimeout: TimeInterval = 5.0
}
enum MenuPosition {
case nearCursor
case screenCenter
case custom(CGPoint)
}Effort Estimate
- Total: ~300 lines across 4 files
- Duration: 2 days
- Complexity: Low-Medium (straightforward window management)
Dependencies
- Blocks: None
- Blocked by: Overlay Context Integration ticket (data model reuse)
Success Criteria
- ✅ Menu appears when overlay is hidden
- ✅ Shows only mapped keys for active context
- ✅ Positioned appropriately (near cursor or center)
- ✅ Auto-dismisses after timeout or action
- ✅ User can choose overlay vs standalone via settings
- ✅ Works for all context types (window, launcher, etc.)
Future Enhancements (Not in Scope)
- Multiple menu styles/themes
- Custom positioning per context
- Keyboard-only navigation (arrow keys)
- Pin menu to stay visible
References
- Design doc:
docs/features/leader-key-overlay-integration.md(Phase 2) - Prerequisite: Overlay Context Integration ticket
- Related: MAL-38 (leader key visual menu)
Metadata
Metadata
Assignees
Labels
No labels