WIP: hide empty collection count pills

This commit is contained in:
Akshay Kolli
2026-06-30 10:39:33 -07:00
parent 7b16aa9aa3
commit 40da0200c6
3 changed files with 34 additions and 9 deletions

View File

@@ -49,15 +49,16 @@ Use this checklist before a release or after changes to panel, pasteboard, setti
16. Return to Clipboard, select a card, use its Collect button to choose Client Work, and confirm the Client Work chip count increases. 16. Return to Clipboard, select a card, use its Collect button to choose Client Work, and confirm the Client Work chip count increases.
17. Select the Client Work chip and confirm the rail filters to assigned items, cards use the Client Work name/color in their headers, and the collection/color/assignment persists after quitting and reopening ClipBored. 17. Select the Client Work chip and confirm the rail filters to assigned items, cards use the Client Work name/color in their headers, and the collection/color/assignment persists after quitting and reopening ClipBored.
18. Right-click the Client Work chip, choose Edit Collection..., rename it, change its color, and confirm the chip and assigned card headers update. 18. Right-click the Client Work chip, choose Edit Collection..., rename it, change its color, and confirm the chip and assigned card headers update.
19. Right-click a media, file, link, PDF, audio, or text card, choose Rename..., give it a title, and confirm the card title and search results use the custom title while paste/copy still uses the original payload. 19. Confirm collection chips with 0 clips do not show a visible count pill, while chips with clips still show their counts.
20. Double-click an item and confirm it attempts to paste or falls back to copy without creating a duplicate history entry. 20. Right-click a media, file, link, PDF, audio, or text card, choose Rename..., give it a title, and confirm the card title and search results use the custom title while paste/copy still uses the original payload.
21. Right-click a card, use Capture Rules to ignore its source app, copy from that app again, and confirm the new item is skipped. 21. Double-click an item and confirm it attempts to paste or falls back to copy without creating a duplicate history entry.
22. Drag an unassigned card onto the renamed collection chip and confirm the chip count increases and the card appears when that collection is selected. 22. Right-click a card, use Capture Rules to ignore its source app, copy from that app again, and confirm the new item is skipped.
23. Resize or test on a narrow display and confirm the bottom shelf switches to compact cards that still show two recent clips cleanly. 23. Drag an unassigned card onto the renamed collection chip and confirm the chip count increases and the card appears when that collection is selected.
24. Select a file, rich text, or URL card and confirm the selected-card rail exposes `Paste Plain Text`, the corner source/kind badge remains visible, and on a narrow shelf secondary actions collapse behind `More` instead of overflowing the card. 24. Resize or test on a narrow display and confirm the bottom shelf switches to compact cards that still show two recent clips cleanly.
25. Confirm card footers do not show `Unknown` for clips without a source app, and confirm used clips show their usage count beside the source app. 25. Select a file, rich text, or URL card and confirm the selected-card rail exposes `Paste Plain Text`, the corner source/kind badge remains visible, and on a narrow shelf secondary actions collapse behind `More` instead of overflowing the card.
26. Confirm card headers use readable relative ages such as `3 minutes ago` or `2 hours ago`, including when viewing a named collection. 26. Confirm card footers do not show `Unknown` for clips without a source app, and confirm used clips show their usage count beside the source app.
27. Confirm the selected card shows a green corner Stack control, the action rail does not duplicate Stack, and clips added to Stack keep a visible corner indicator when selection moves away. 27. Confirm card headers use readable relative ages such as `3 minutes ago` or `2 hours ago`, including when viewing a named collection.
28. Confirm the selected card shows a green corner Stack control, the action rail does not duplicate Stack, and clips added to Stack keep a visible corner indicator when selection moves away.
## Copy And Paste ## Copy And Paste

View File

@@ -1493,6 +1493,11 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate {
return ClipboardSortMode.allCases.compactMap { collectionButtons[$0]?.count } return ClipboardSortMode.allCases.compactMap { collectionButtons[$0]?.count }
} }
var debugCollectionCountLabelHiddenStates: [Bool] {
updateCollectionButtons()
return ClipboardSortMode.allCases.compactMap { collectionButtons[$0]?.debugCountLabelIsHidden }
}
var debugCollectionChipAccessibilityLabels: [String] { var debugCollectionChipAccessibilityLabels: [String] {
updateCollectionButtons() updateCollectionButtons()
return ClipboardSortMode.allCases.compactMap { collectionButtons[$0]?.accessibilityLabel() } return ClipboardSortMode.allCases.compactMap { collectionButtons[$0]?.accessibilityLabel() }
@@ -1565,6 +1570,11 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate {
return viewModel.collectionNames.compactMap { customCollectionButtons[$0]?.count } return viewModel.collectionNames.compactMap { customCollectionButtons[$0]?.count }
} }
var debugCustomCollectionCountLabelHiddenStates: [Bool] {
updateCollectionButtons()
return viewModel.collectionNames.compactMap { customCollectionButtons[$0]?.debugCountLabelIsHidden }
}
var debugCustomCollectionColorHexes: [String: String] { var debugCustomCollectionColorHexes: [String: String] {
Dictionary(uniqueKeysWithValues: viewModel.collectionNames.map { name in Dictionary(uniqueKeysWithValues: viewModel.collectionNames.map { name in
(name, ClipboardCollectionVisuals.hexString(for: collectionColor(forCollectionNamed: name))) (name, ClipboardCollectionVisuals.hexString(for: collectionColor(forCollectionNamed: name)))
@@ -2109,6 +2119,7 @@ private final class CollectionChipView: NSView {
? NSColor.controlAccentColor.withAlphaComponent(0.16) ? NSColor.controlAccentColor.withAlphaComponent(0.16)
: NSColor.labelColor.withAlphaComponent(0.07) : NSColor.labelColor.withAlphaComponent(0.07)
).cgColor ).cgColor
updateCountLabelVisibility()
updateAccessibility() updateAccessibility()
updateChrome() updateChrome()
} }
@@ -2138,9 +2149,14 @@ private final class CollectionChipView: NSView {
func setCount(_ count: Int) { func setCount(_ count: Int) {
self.count = count self.count = count
countLabel.stringValue = count > 999 ? "999+" : "\(count)" countLabel.stringValue = count > 999 ? "999+" : "\(count)"
updateCountLabelVisibility()
updateAccessibility() updateAccessibility()
} }
private func updateCountLabelVisibility() {
countLabel.isHidden = count == 0
}
private func updateAccessibility() { private func updateAccessibility() {
let noun = count == 1 ? "clip" : "clips" let noun = count == 1 ? "clip" : "clips"
let selectedText = isSelected ? "selected, " : "" let selectedText = isSelected ? "selected, " : ""
@@ -2291,6 +2307,10 @@ private final class CollectionChipView: NSView {
isKeyboardFocused isKeyboardFocused
} }
var debugCountLabelIsHidden: Bool {
countLabel.isHidden
}
func debugDropItem(_ itemID: UUID) { func debugDropItem(_ itemID: UUID) {
onDropItem?(itemID) onDropItem?(itemID)
} }

View File

@@ -223,6 +223,7 @@ final class ClipboardPanelViewTests: XCTestCase {
fixture.window.contentView?.layoutSubtreeIfNeeded() fixture.window.contentView?.layoutSubtreeIfNeeded()
XCTAssertEqual(fixture.view.debugCollectionChipAcceptsFirstResponder, Array(repeating: true, count: ClipboardSortMode.allCases.count)) XCTAssertEqual(fixture.view.debugCollectionChipAcceptsFirstResponder, Array(repeating: true, count: ClipboardSortMode.allCases.count))
XCTAssertEqual(fixture.view.debugCollectionCountLabelHiddenStates, Array(repeating: true, count: ClipboardSortMode.allCases.count))
XCTAssertEqual(fixture.view.debugCollectionChipAccessibilityLabels.first, "Clipboard, selected, 0 clips") XCTAssertEqual(fixture.view.debugCollectionChipAccessibilityLabels.first, "Clipboard, selected, 0 clips")
XCTAssertTrue(fixture.view.debugFocusCollectionChip(.links)) XCTAssertTrue(fixture.view.debugFocusCollectionChip(.links))
@@ -326,6 +327,7 @@ final class ClipboardPanelViewTests: XCTestCase {
XCTAssertEqual(fixture.viewModel.statusMessage, "Created Research Stack") XCTAssertEqual(fixture.viewModel.statusMessage, "Created Research Stack")
XCTAssertEqual(fixture.view.debugCustomCollectionTitles, ["Research Stack"]) XCTAssertEqual(fixture.view.debugCustomCollectionTitles, ["Research Stack"])
XCTAssertEqual(fixture.view.debugCustomCollectionCounts, [0]) XCTAssertEqual(fixture.view.debugCustomCollectionCounts, [0])
XCTAssertEqual(fixture.view.debugCustomCollectionCountLabelHiddenStates, [true])
XCTAssertEqual(fixture.view.debugSelectedCollectionTitle, "Research Stack") XCTAssertEqual(fixture.view.debugSelectedCollectionTitle, "Research Stack")
XCTAssertEqual(fixture.view.debugVisibleCardCount, 0) XCTAssertEqual(fixture.view.debugVisibleCardCount, 0)
XCTAssertEqual(fixture.view.debugEmptyStateText?.title, "No clips in Research Stack") XCTAssertEqual(fixture.view.debugEmptyStateText?.title, "No clips in Research Stack")
@@ -624,6 +626,7 @@ final class ClipboardPanelViewTests: XCTestCase {
XCTAssertEqual(fixture.viewModel.visibleItems.count, 6) XCTAssertEqual(fixture.viewModel.visibleItems.count, 6)
XCTAssertEqual(ClipboardSortMode.allCases.map { fixture.viewModel.collectionCount(for: $0) }, [6, 6, 2, 1, 1, 1, 1, 1]) XCTAssertEqual(ClipboardSortMode.allCases.map { fixture.viewModel.collectionCount(for: $0) }, [6, 6, 2, 1, 1, 1, 1, 1])
XCTAssertEqual(fixture.view.debugCollectionCounts, [6, 6, 2, 1, 1, 1, 1, 1]) XCTAssertEqual(fixture.view.debugCollectionCounts, [6, 6, 2, 1, 1, 1, 1, 1])
XCTAssertEqual(fixture.view.debugCollectionCountLabelHiddenStates, Array(repeating: false, count: ClipboardSortMode.allCases.count))
} }
func testCollectionRailShowsAssignedCollections() { func testCollectionRailShowsAssignedCollections() {
@@ -642,6 +645,7 @@ final class ClipboardPanelViewTests: XCTestCase {
XCTAssertEqual(fixture.view.debugCustomCollectionTitles, ["Useful Links", "Important Notes", "Client Work"]) XCTAssertEqual(fixture.view.debugCustomCollectionTitles, ["Useful Links", "Important Notes", "Client Work"])
XCTAssertEqual(fixture.view.debugCustomCollectionCounts, [1, 1, 1]) XCTAssertEqual(fixture.view.debugCustomCollectionCounts, [1, 1, 1])
XCTAssertEqual(fixture.view.debugCustomCollectionCountLabelHiddenStates, [false, false, false])
fixture.viewModel.selectCollection(named: "Useful Links") fixture.viewModel.selectCollection(named: "Useful Links")
drainMainQueue() drainMainQueue()