Redesign emoji + suggestion popups as a shared minimal dark HUD#753
Open
FuJacob wants to merge 4 commits into
Open
Redesign emoji + suggestion popups as a shared minimal dark HUD#753FuJacob wants to merge 4 commits into
FuJacob wants to merge 4 commits into
Conversation
The :emoji: picker and the suggestion "popup" card each carried their own .regularMaterial styling and had drifted apart. Route both (plus the macro preview) through one committed-dark HUD (PopupChrome) so they read as ephemeral overlays instead of bright cards, identical dark over light and dark hosts. The emoji picker becomes a compact two-row layout: the live :query on top, a horizontal ribbon of ranked glyphs below, moved with the arrow keys (Left/Right now navigate the ribbon; previously they dismissed it). The suggestion card is darker and a touch slimmer, and onboarding's emoji replica is updated to match.
Adpros7
added a commit
to Adpros7/cotabby
that referenced
this pull request
Jun 23, 2026
…popups) into integration/merge-all
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes the two floating popups feel like ephemeral system overlays instead of bright cards competing with the document. The
:emoji:picker and the suggestion popup card (mirror mode) each carried their own.regularMaterialstyling and had drifted apart; both now route through one shared, committed-dark HUD (PopupChrome) that reads the same dark over a white host as over a dark one. The emoji picker is also restructured from a tall vertical list into a compact two-row layout: the live:queryon top, a horizontal ribbon of ranked glyphs below, moved with the arrow keys.Validation
Rendered the redesigned popups over both a light and a dark host with an
ImageRendererharness (since removed): the committed-dark chrome, hairline, and light text are identical across host appearances, and the ribbon's soft selection chip lands on the highlighted glyph. (ImageRendererdoes not lay outScrollViewsubviews, so the real ribbon row snapshots blank; verified the cells via a non-scrolling proxy. The liveNSHostingViewpanel scrolls normally.)Linked issues
None.
Risk / rollout notes
Cotabby/UI/PopupChrome.swift-> ranxcodegen generate; theproject.pbxprojchange is only the added file reference.MirrorOverlayLayoutand its geometry tests were updated in lockstep.DemoEmojiPopup) was updated to the new ribbon so onboarding doesn't show a stale design.Greptile Summary
This PR consolidates the emoji picker, suggestion popup card, and macro inline preview into a single shared dark HUD (
PopupChrome), replacing per-surface.regularMaterialstyling with a deterministic charcoal gradient that reads identically over both light and dark host documents. The emoji picker is also restructured from a scrollable vertical list into a compact two-row layout (:queryrow + horizontal glyph ribbon) with Left/Right arrow navigation.PopupChrome.swiftintroducesPopupTheme(tokens) andPopupHUDChrome(modifier), applied uniformly acrossEmojiPickerView,InlinePreviewView, andMirrorOverlayView— reducing per-site color branching to zero.EmojiPickerControllerremaps Left/Right arrows fromdismissExternallytonavigate(.up/.down), with pass-through preserved when no matches are present; three new controller tests cover all branches.MirrorOverlayLayoutremoves theminCardWidthfloor so cards hug short suggestions, and trimsverticalPaddingfrom 6→4 in lockstep with the view change; geometry tests were updated accordingly.Confidence Score: 5/5
Safe to merge. The changes are scoped to visual chrome and keyboard routing with no persistence, settings, or schema impact, and all new behavior is covered by tests.
The shared
PopupChromeis a well-contained new file with deterministic, non-adaptive styling applied consistently across three surfaces. The arrow-key behavior change inEmojiPickerControlleris explicit, fully commented, and covered by three new tests that verify both the consume and pass-through branches. Layout metric changes inMirrorOverlayLayoutare reflected in the updated geometry tests. No logic paths were left untested or undocumented.No files require special attention. The only nits are in the onboarding demo replica, which does not affect production behavior.
Important Files Changed
PopupThemecentralises all visual tokens;PopupHUDChromemodifier correctly applies background, hairline overlay, clip shape, and forced dark environment. Design is clean and well-documented.EmojiPickerMetricsconstants throughout, animatedScrollViewReadercentering on selection change, and de-publishedacceptKeyLabelas intended. No issues.DemoEmojiRibbonCellcorrectly usesEmojiPickerMetrics.cellSize, butDemoEmojiPopupstill hardcodes frame width (174) and raw spacing/padding literals instead of the shared metrics constants.117(Forward-Delete) case correctly kept asdismissExternally. New controller tests cover all three branches.minCardWidthfloor so the card hugs short suggestions;verticalPaddingdropped from 6→4 in lockstep with the view padding change. Geometry tests updated consistently.backdropColor/borderColorhelpers removed; ghost text now uses fixed dark-scheme values.popupHUDChrome()applied; vertical padding reduced from 6→4.colorSchemeenvironment property removed as no longer needed..regularMaterialtopopupHUDChrome(); keycap colors updated to usePopupThemetokens. Height trimmed from 30→28. All changes consistent with the shared chrome contract.Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD KEY[Key event from global tap] CTRL[EmojiPickerController.decideCaptureKey] MATCHES{matches.isEmpty?} KEY --> CTRL CTRL -->|Left 123 / Up 126| NAV_UP[navigate up] CTRL -->|Right 124 / Down 125| NAV_DOWN[navigate down] CTRL -->|Escape| DISMISS[dismiss] CTRL -->|Return / Enter| DISMISS_EXT[dismissExternally] CTRL -->|Forward-Delete 117| DISMISS_EXT NAV_UP --> MATCHES NAV_DOWN --> MATCHES MATCHES -->|No| PASSTHROUGH[passThrough: host caret moves, capture closes] MATCHES -->|Yes| CONSUME[consume: selectedIndex updates, ribbon scrolls] CONSUME --> VIEW[EmojiPickerView] VIEW --> RIBBON[HStack ribbon] VIEW --> QUERYROW[queryRow] RIBBON -->|onChange selectedIndex| SCROLL[proxy.scrollTo center, animated]%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD KEY[Key event from global tap] CTRL[EmojiPickerController.decideCaptureKey] MATCHES{matches.isEmpty?} KEY --> CTRL CTRL -->|Left 123 / Up 126| NAV_UP[navigate up] CTRL -->|Right 124 / Down 125| NAV_DOWN[navigate down] CTRL -->|Escape| DISMISS[dismiss] CTRL -->|Return / Enter| DISMISS_EXT[dismissExternally] CTRL -->|Forward-Delete 117| DISMISS_EXT NAV_UP --> MATCHES NAV_DOWN --> MATCHES MATCHES -->|No| PASSTHROUGH[passThrough: host caret moves, capture closes] MATCHES -->|Yes| CONSUME[consume: selectedIndex updates, ribbon scrolls] CONSUME --> VIEW[EmojiPickerView] VIEW --> RIBBON[HStack ribbon] VIEW --> QUERYROW[queryRow] RIBBON -->|onChange selectedIndex| SCROLL[proxy.scrollTo center, animated]Comments Outside Diff (1)
Cotabby/Support/EmojiPickerPanelLayout.swift, line 1-12 (link)The old "Pure geometry for the emoji picker panel: how big it is…" paragraph and the new "Pure geometry for the two-row emoji picker…" paragraph were both left as a single contiguous doc comment block before the
EmojiPickerMetricsenum. Only one should be the file overview; the other is now redundant or misplaced as an enum-level doc comment.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Reviews (3): Last reviewed commit: "Fix mirror layout clamp test" | Re-trigger Greptile