diff --git a/docs/SMOKE_TEST.md b/docs/SMOKE_TEST.md index 6fe378d..7c9bbd8 100644 --- a/docs/SMOKE_TEST.md +++ b/docs/SMOKE_TEST.md @@ -62,6 +62,7 @@ Use this checklist before a release or after changes to panel, pasteboard, setti 29. Confirm single-line text cards do not repeat the same text in both title and body, while multi-line text cards show the remaining lines below the first line. 30. Confirm the Pinned empty state points to the Pin action instead of a plain-key shortcut. 31. Confirm each card's source or type badge reads as an attached header-corner tile instead of a small floating icon. +32. Confirm built-in collection chips use recognizable glyphs, while custom collection chips keep color-dot swatches. ## Copy And Paste diff --git a/sources/clipbored/views/ClipboardPanelView.swift b/sources/clipbored/views/ClipboardPanelView.swift index bd9901c..de1f4bb 100644 --- a/sources/clipbored/views/ClipboardPanelView.swift +++ b/sources/clipbored/views/ClipboardPanelView.swift @@ -224,7 +224,7 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate { private let collectionScrollView = HorizontalRailScrollView() private let collectionStack = NSStackView() private let addCollectionButton = NSButton() - private let stackChip = CollectionChipView(title: "Stack", color: .systemGreen) + private let stackChip = CollectionChipView(title: "Stack", color: .systemGreen, symbolName: "square.stack.3d.up.fill") private let itemsStack = NSStackView() private let scrollView = HorizontalRailScrollView() private let statusLabel = NSTextField(labelWithString: "") @@ -542,7 +542,7 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate { } for mode in ClipboardSortMode.allCases { - let chip = CollectionChipView(title: collectionTitle(for: mode), color: collectionColor(for: mode)) + let chip = CollectionChipView(title: collectionTitle(for: mode), color: collectionColor(for: mode), symbolName: collectionSymbol(for: mode)) chip.toolTip = mode.title chip.onPress = { [weak self] in self?.viewModel.sortMode = mode @@ -642,6 +642,19 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate { } } + private func collectionSymbol(for mode: ClipboardSortMode) -> String { + switch mode { + case .mostRecent: return "doc.on.clipboard" + case .mostUsed: return "chart.bar.fill" + case .text: return "text.alignleft" + case .links: return "link" + case .images: return "photo" + case .audio: return "music.note" + case .files: return "doc.fill" + case .pinned: return "pin.fill" + } + } + private func collectionColor(for mode: ClipboardSortMode) -> NSColor { ClipboardCollectionVisuals.color(for: mode) } @@ -1486,6 +1499,10 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate { ClipboardSortMode.allCases.compactMap { collectionButtons[$0]?.titleText } } + var debugCollectionLeadingSymbols: [String] { + ClipboardSortMode.allCases.compactMap { collectionButtons[$0]?.debugLeadingSymbolName } + } + var debugSelectedCollectionTitle: String? { if stackChip.isSelected { return stackChip.titleText @@ -2036,7 +2053,9 @@ private final class RailEdgeFadeView: NSView { private final class CollectionChipView: NSView { let titleText: String private let color: NSColor + private let symbolName: String? private let dot = NSView() + private let symbolView = NSImageView() private let label: NSTextField private let countLabel = NSTextField(labelWithString: "0") private(set) var isSelected = false @@ -2052,9 +2071,10 @@ private final class CollectionChipView: NSView { var onEdit: (() -> Void)? var onDelete: (() -> Void)? - init(title: String, color: NSColor) { + init(title: String, color: NSColor, symbolName: String? = nil) { self.titleText = title self.color = color + self.symbolName = symbolName self.label = NSTextField(labelWithString: title) super.init(frame: .zero) configure() @@ -2082,6 +2102,20 @@ private final class CollectionChipView: NSView { dot.widthAnchor.constraint(equalToConstant: 8).isActive = true dot.heightAnchor.constraint(equalToConstant: 8).isActive = true + let leadingIndicator: NSView + if let symbolName { + let image = NSImage(systemSymbolName: symbolName, accessibilityDescription: titleText) + image?.isTemplate = true + symbolView.image = image + symbolView.imageScaling = .scaleProportionallyUpOrDown + symbolView.contentTintColor = color.withAlphaComponent(0.86) + symbolView.widthAnchor.constraint(equalToConstant: 13).isActive = true + symbolView.heightAnchor.constraint(equalToConstant: 13).isActive = true + leadingIndicator = symbolView + } else { + leadingIndicator = dot + } + label.font = .systemFont(ofSize: NSFont.smallSystemFontSize, weight: .medium) label.textColor = .secondaryLabelColor label.lineBreakMode = .byTruncatingTail @@ -2101,7 +2135,7 @@ private final class CollectionChipView: NSView { countLabel.heightAnchor.constraint(equalToConstant: 16).isActive = true countLabel.setContentCompressionResistancePriority(.required, for: .horizontal) - let stack = NSStackView(views: [dot, label, countLabel]) + let stack = NSStackView(views: [leadingIndicator, label, countLabel]) stack.orientation = .horizontal stack.alignment = .centerY stack.spacing = 6 @@ -2124,9 +2158,10 @@ private final class CollectionChipView: NSView { countLabel.textColor = selected ? .labelColor : .tertiaryLabelColor countLabel.layer?.backgroundColor = ( selected - ? NSColor.controlAccentColor.withAlphaComponent(0.16) + ? color.withAlphaComponent(0.16) : NSColor.labelColor.withAlphaComponent(0.07) ).cgColor + symbolView.contentTintColor = color.withAlphaComponent(selected ? 0.98 : 0.78) updateCountLabelVisibility() updateAccessibility() updateChrome() @@ -2143,11 +2178,11 @@ private final class CollectionChipView: NSView { layer?.backgroundColor = color.withAlphaComponent(0.18).cgColor layer?.borderColor = color.withAlphaComponent(0.68).cgColor } else if isSelected { - layer?.backgroundColor = NSColor.windowBackgroundColor.withAlphaComponent(0.58).cgColor - layer?.borderColor = NSColor.controlAccentColor.withAlphaComponent(isKeyboardFocused ? 0.74 : 0.34).cgColor + layer?.backgroundColor = color.withAlphaComponent(0.13).cgColor + layer?.borderColor = color.withAlphaComponent(isKeyboardFocused ? 0.72 : 0.38).cgColor } else if isKeyboardFocused { - layer?.backgroundColor = NSColor.windowBackgroundColor.withAlphaComponent(0.34).cgColor - layer?.borderColor = NSColor.controlAccentColor.withAlphaComponent(0.52).cgColor + layer?.backgroundColor = color.withAlphaComponent(0.09).cgColor + layer?.borderColor = color.withAlphaComponent(0.44).cgColor } else { layer?.backgroundColor = NSColor.clear.cgColor layer?.borderColor = NSColor.clear.cgColor @@ -2319,6 +2354,10 @@ private final class CollectionChipView: NSView { countLabel.isHidden } + var debugLeadingSymbolName: String { + symbolName ?? "" + } + func debugDropItem(_ itemID: UUID) { onDropItem?(itemID) } diff --git a/tests/clipboredtests/ClipboardPanelViewTests.swift b/tests/clipboredtests/ClipboardPanelViewTests.swift index 58d9b8a..680610d 100644 --- a/tests/clipboredtests/ClipboardPanelViewTests.swift +++ b/tests/clipboredtests/ClipboardPanelViewTests.swift @@ -229,6 +229,10 @@ final class ClipboardPanelViewTests: XCTestCase { fixture.view.debugCollectionTitles, ["Clipboard", "Frequent", "Text", "Links", "Images", "Audio", "Files", "Pinned"] ) + XCTAssertEqual( + fixture.view.debugCollectionLeadingSymbols, + ["doc.on.clipboard", "chart.bar.fill", "text.alignleft", "link", "photo", "music.note", "doc.fill", "pin.fill"] + ) XCTAssertEqual(fixture.view.debugSelectedCollectionTitle, "Clipboard") fixture.viewModel.sortMode = .links