fix: place notes actions beside scrollable formatting controls

This commit is contained in:
2026-10-19 22:37:22 +02:00
parent bb640867b7
commit 1804f679fc
2 changed files with 22 additions and 8 deletions
+2 -2
View File
@@ -68,7 +68,7 @@ Right-click the launcher background for Settings and Quit. Actions include favor
Action and selection popups paint a popup-sized background using the launcher window’s gradient coordinates, keeping the glows continuous without showing the results underneath. Each opening rebuilds the complete native view and layer tree, rather than resizing a retained presentation between the footer and header. Callbacks and selection behavior stay in the controller. Layout finishes before the opening fade, including when switching popup types.
The launcher, emoji picker, Translate, and Notes share `ActionPill` for styling, alignment, spacing, and keyboard indicators: primary action first, then Actions with separate Command and K keycaps. Notes places Browse Notes (Command-P) and Actions (Command-K) in its title-bar pill; New Note remains in Actions and on Command-N. Controllers supply the buttons and retain their targets, enabled state, and popup behavior.
The launcher, emoji picker, Translate, and Notes share `ActionPill` for footer styling, alignment, spacing, and keyboard indicators: primary action first, then Actions with separate Command and K keycaps. Notes places Browse Notes (Command-P) and Actions (Command-K) at the bottom right; New Note remains in Actions and on Command-N. Its formatting controls scroll horizontally when the remaining footer space is too narrow. Controllers supply the buttons and retain their targets, enabled state, and popup behavior.
The header’s trailing edge is constrained to the footer’s trailing edge. The translation provider pill and footer pill therefore share the same 8-point right inset and 36-point height.
@@ -145,7 +145,7 @@ Actions (Command-K) opens the same searchable popup style used throughout Conjur
The bottom strip applies Markdown headings, bold, italic, strikethrough, inline code, links, fenced code blocks, quotes, numbered lists, bullet lists, and checklists. Formatting preserves embedded images and supports Undo. List buttons convert existing list types; clicking the current type removes its marker. The formatting strip is always visible. Successful autosaves stay unobtrusive; only save, load, or deletion errors appear below the editor.
Note text fades over 16 points at the editor’s scroll edges rather than clipping sharply above the formatting strip. Matching 16-point scroll insets keep the first and last lines clear of the fade when scrolled to either end. The 36-point action-pill header and 28-point formatting strip meet the editor without extra vertical gaps.
Note text fades over 16 points at the editor’s scroll edges rather than clipping sharply above the formatting strip. Matching 16-point scroll insets keep the first and last lines clear of the fade when scrolled to either end. The 36-point title header and footer meet the editor without extra vertical gaps.
Formatting shortcuts use the same actions as the bottom strip. They apply to the editor’s current selection or caret, never to text in an open picker. Hover over a formatting button to see its shortcut. Command-K remains Actions.
+20 -6
View File
@@ -62,16 +62,15 @@ final class NotesController: NSViewController, NSTextViewDelegate {
noteTitle.lineBreakMode = .byTruncatingTail
noteTitle.setAccessibilityLabel("Note title")
let header = NSView()
for control in [noteTitle, controls] {
for control in [noteTitle] {
control.translatesAutoresizingMaskIntoConstraints = false
header.addSubview(control)
control.centerYAnchor.constraint(equalTo: header.centerYAnchor).isActive = true
}
NSLayoutConstraint.activate([
controls.trailingAnchor.constraint(equalTo: header.trailingAnchor, constant: -8),
noteTitle.centerXAnchor.constraint(equalTo: header.centerXAnchor),
noteTitle.leadingAnchor.constraint(greaterThanOrEqualTo: header.leadingAnchor, constant: 44),
noteTitle.trailingAnchor.constraint(lessThanOrEqualTo: controls.leadingAnchor, constant: -16),
noteTitle.trailingAnchor.constraint(lessThanOrEqualTo: header.trailingAnchor, constant: -44),
])
actions.closed = { [weak self] in self?.focusEditor() }
actions.selectNote = { [weak self] in self?.switchNote($0) }
@@ -92,7 +91,22 @@ final class NotesController: NSViewController, NSTextViewDelegate {
formatting.addArrangedSubview(button)
}
formatting.spacing = 8
let footer = NSStackView(views: [formatting, NSView()])
let formattingScroll = NSScrollView()
formattingScroll.drawsBackground = false
formattingScroll.contentView.drawsBackground = false
formattingScroll.hasHorizontalScroller = true
formattingScroll.autohidesScrollers = true
formattingScroll.scrollerStyle = .overlay
formattingScroll.verticalScrollElasticity = .none
formattingScroll.documentView = formatting
formatting.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
formatting.widthAnchor.constraint(equalToConstant: CGFloat(tools.count * 28 + (tools.count - 1) * 8)),
formatting.heightAnchor.constraint(equalToConstant: 28),
formattingScroll.widthAnchor.constraint(greaterThanOrEqualToConstant: 28),
formattingScroll.heightAnchor.constraint(equalToConstant: 36),
])
let footer = NSStackView(views: [formattingScroll, controls])
footer.alignment = .centerY
footer.spacing = 8
editor.delegate = self
@@ -149,11 +163,11 @@ final class NotesController: NSViewController, NSTextViewDelegate {
body.bottomAnchor.constraint(equalTo: view.bottomAnchor),
scroll.widthAnchor.constraint(equalTo: body.widthAnchor),
footer.leadingAnchor.constraint(equalTo: body.leadingAnchor, constant: 24),
footer.trailingAnchor.constraint(equalTo: body.trailingAnchor, constant: -6),
footer.trailingAnchor.constraint(equalTo: body.trailingAnchor, constant: -8),
status.leadingAnchor.constraint(equalTo: body.leadingAnchor, constant: 28),
status.trailingAnchor.constraint(equalTo: body.trailingAnchor, constant: -12),
scroll.heightAnchor.constraint(greaterThanOrEqualToConstant: 80),
footer.heightAnchor.constraint(equalToConstant: 28),
footer.heightAnchor.constraint(equalToConstant: 36),
])
guard let store else {
editor.isEditable = false