Skip to content

Commit cc345e2

Browse files
backnotpropclaude
andcommitted
feat: curate default labels, add cyan/amber colors, bare digit shortcuts
Finalize the 10 default quick labels based on user feedback data: clarify, overview, verify, example, patterns, alternatives, regression, out-of-scope, tests, nice-approach. Each label gets a unique color (added cyan and amber to the palette). Bare digit keys (1-0) now apply labels when the picker is open, Alt+N still works everywhere. Tip editor cursor starts at beginning for readability. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 68a9bb8 commit cc345e2

6 files changed

Lines changed: 31 additions & 22 deletions

File tree

packages/ui/components/AnnotationToolbar.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ export const AnnotationToolbar: React.FC<AnnotationToolbarProps> = ({
103103
};
104104
}, [element, positionMode, closeOnScrollOut, onClose]);
105105

106-
// Type-to-comment + Alt+N quick label shortcuts
106+
// Type-to-comment + Alt+N / bare digit quick label shortcuts
107107
useEffect(() => {
108108
const handleKeyDown = (e: KeyboardEvent) => {
109109
if (e.isComposing) return;
@@ -114,10 +114,12 @@ export const AnnotationToolbar: React.FC<AnnotationToolbarProps> = ({
114114
return;
115115
}
116116

117-
// Alt+1..8: apply quick label
118-
if (e.altKey && e.code >= 'Digit1' && e.code <= 'Digit9') {
117+
// Quick label by digit — Alt+N always works, bare digit when picker is open
118+
const isDigit = (e.code >= 'Digit1' && e.code <= 'Digit9') || e.code === 'Digit0';
119+
if (isDigit && !e.ctrlKey && !e.metaKey && (e.altKey || showQuickLabels)) {
119120
e.preventDefault();
120-
const index = parseInt(e.code.slice(5), 10) - 1;
121+
const digit = parseInt(e.code.slice(5), 10);
122+
const index = digit === 0 ? 9 : digit - 1;
121123
if (index < quickLabels.length) {
122124
onQuickLabel?.(quickLabels[index]);
123125
}
@@ -133,7 +135,7 @@ export const AnnotationToolbar: React.FC<AnnotationToolbarProps> = ({
133135

134136
window.addEventListener("keydown", handleKeyDown);
135137
return () => window.removeEventListener("keydown", handleKeyDown);
136-
}, [onClose, onRequestComment, onQuickLabel, quickLabels]);
138+
}, [onClose, onRequestComment, onQuickLabel, quickLabels, showQuickLabels]);
137139

138140
useDismissOnOutsideAndEscape({
139141
enabled: !showQuickLabels,

packages/ui/components/FloatingQuickLabelPicker.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,20 @@ export const FloatingQuickLabelPicker: React.FC<FloatingQuickLabelPickerProps> =
6565
};
6666
}, [anchorEl, cursorHint]);
6767

68-
// Keyboard: Alt+1..8 and Escape
68+
// Keyboard: 1-9/0 or Alt+1-9/0 to apply label, Escape to dismiss
6969
useEffect(() => {
7070
const handleKeyDown = (e: KeyboardEvent) => {
7171
if (e.key === 'Escape') {
7272
e.preventDefault();
7373
onDismiss();
7474
return;
7575
}
76-
if (e.altKey && e.code >= 'Digit1' && e.code <= 'Digit9') {
76+
// Accept bare digit or Alt+digit — picker is open so digits mean labels
77+
const isDigit = (e.code >= 'Digit1' && e.code <= 'Digit9') || e.code === 'Digit0';
78+
if (isDigit && !e.ctrlKey && !e.metaKey) {
7779
e.preventDefault();
78-
const index = parseInt(e.code.slice(5), 10) - 1;
80+
const digit = parseInt(e.code.slice(5), 10);
81+
const index = digit === 0 ? 9 : digit - 1;
7982
if (index < quickLabels.length) {
8083
onSelect(quickLabels[index]);
8184
}

packages/ui/components/KeyboardShortcuts.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ const planShortcuts: ShortcutSection[] = [
9494
title: 'Annotations',
9595
shortcuts: [
9696
{ keys: ['a-z'], desc: 'Start typing comment', hint: 'When the annotation toolbar is open, any letter key opens the comment editor with that character' },
97-
{ keys: [alt, '1-9'], desc: 'Apply quick label', hint: 'When the toolbar or label picker is open, instantly applies the Nth preset label' },
97+
{ keys: [alt, '1-0'], desc: 'Apply quick label', hint: 'Instantly applies the Nth preset label (0 = 10th). When the label picker is open, bare digits also work.' },
9898
{ keys: [mod, enter], desc: 'Submit comment' },
9999
{ keys: [mod, 'C'], desc: 'Copy selected text' },
100100
{ keys: ['Esc'], desc: 'Close toolbar / Cancel' },

packages/ui/components/QuickLabelDropdown.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ export const QuickLabelDropdown: React.FC<{
5050
{label.text}
5151
</span>
5252
{/* Shortcut hint */}
53-
{index < 9 && (
53+
{index < 10 && (
5454
<span className="text-[9px] tabular-nums text-muted-foreground/40 group-hover:text-muted-foreground/60 flex-shrink-0 font-mono">
55-
{index + 1}
55+
{index === 9 ? '0' : index + 1}
5656
</span>
5757
)}
5858
</button>

packages/ui/components/Settings.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ export const Settings: React.FC<SettingsProps> = ({ taterMode, onTaterModeChange
713713
))}
714714
</select>
715715
<span className="text-[10px] text-muted-foreground/50 font-mono w-8 text-center flex-shrink-0">
716-
{index < 9 ? `${navigator.platform?.includes('Mac') ? '⌥' : 'Alt+'}${index + 1}` : ''}
716+
{index < 10 ? `${navigator.platform?.includes('Mac') ? '⌥' : 'Alt+'}${index === 9 ? '0' : index + 1}` : ''}
717717
</span>
718718
<button
719719
onClick={() => {
@@ -756,6 +756,7 @@ export const Settings: React.FC<SettingsProps> = ({ taterMode, onTaterModeChange
756756
placeholder="AI instruction tip..."
757757
className="flex-1 px-2 py-1 bg-background/60 rounded text-[10px] text-muted-foreground placeholder:text-muted-foreground/30 focus:outline-none focus:ring-1 focus:ring-primary/50"
758758
autoFocus
759+
onFocus={(e) => { e.target.setSelectionRange(0, 0); e.target.scrollLeft = 0; }}
759760
/>
760761
<button
761762
onClick={() => {
@@ -799,7 +800,7 @@ export const Settings: React.FC<SettingsProps> = ({ taterMode, onTaterModeChange
799800
)}
800801

801802
<div className="text-[10px] text-muted-foreground/70">
802-
Use {navigator.platform?.includes('Mac') ? '⌥' : 'Alt+'}1 through {navigator.platform?.includes('Mac') ? '⌥' : 'Alt+'}9 when the annotation toolbar is visible to apply a label instantly.
803+
Use {navigator.platform?.includes('Mac') ? '⌥' : 'Alt+'}1 through {navigator.platform?.includes('Mac') ? '⌥' : 'Alt+'}0 when the annotation toolbar is visible to apply a label instantly.
803804
</div>
804805
</>
805806
)}

packages/ui/utils/quickLabels.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,21 @@ export const LABEL_COLOR_MAP: Record<string, { bg: string; text: string; darkTex
2727
teal: { bg: 'rgba(20,184,166,0.15)', text: '#0d9488', darkText: '#2dd4bf' },
2828
pink: { bg: 'rgba(236,72,153,0.15)', text: '#db2777', darkText: '#f472b6' },
2929
green: { bg: 'rgba(34,197,94,0.15)', text: '#16a34a', darkText: '#4ade80' },
30+
cyan: { bg: 'rgba(8,145,178,0.15)', text: '#0891b2', darkText: '#22d3ee' },
31+
amber: { bg: 'rgba(180,83,9,0.15)', text: '#b45309', darkText: '#fbbf24' },
3032
};
3133

3234
export const DEFAULT_QUICK_LABELS: QuickLabel[] = [
33-
{ id: 'clarify-this', emoji: '❓', text: 'Clarify this', color: 'yellow' },
34-
{ id: 'needs-tests', emoji: '🧪', text: 'Needs tests', color: 'blue' },
35-
{ id: 'consider-edge-cases', emoji: '🧩', text: 'Consider edge cases', color: 'teal' },
36-
{ id: 'missing-overview', emoji: '🗺️', text: 'Missing overview', color: 'purple', tip: 'Provide a narrative overview of what is being built, why it is being built, and how it will be built. Add this before the implementation details.' },
37-
{ id: 'security-concern', emoji: '🔒', text: 'Security concern', color: 'red' },
38-
{ id: 'break-this-up', emoji: '✂️', text: 'Break this up', color: 'orange' },
39-
{ id: 'wrong-order', emoji: '🔀', text: 'Wrong order', color: 'purple' },
40-
{ id: 'discuss-first', emoji: '💬', text: 'Discuss first', color: 'pink' },
41-
{ id: 'nice-approach', emoji: '👍', text: 'Nice approach', color: 'green' },
35+
{ id: 'clarify-this', emoji: '❓', text: 'Clarify this', color: 'yellow' },
36+
{ id: 'missing-overview', emoji: '🗺️', text: 'Missing overview', color: 'purple', tip: 'Provide a narrative overview of what is being built, why it is being built, and how it will be built. Add this before the implementation details.' },
37+
{ id: 'verify-this', emoji: '🔍', text: 'Verify this', color: 'orange', tip: 'This seems like an assumption. Verify by reading the actual code before proceeding.' },
38+
{ id: 'give-me-an-example', emoji: '🔬', text: 'Give me an example', color: 'cyan', tip: 'This is too abstract. Show a before/after, a sample input/output, or a specific scenario so I can see how this actually works.' },
39+
{ id: 'match-existing-patterns', emoji: '🧬', text: 'Match existing patterns', color: 'teal', tip: 'Search the codebase for existing patterns, components, or utilities that already solve this. Reuse what exists rather than introducing a new approach.' },
40+
{ id: 'consider-alternatives', emoji: '🔄', text: 'Consider alternatives', color: 'pink', tip: 'Propose 2-3 alternative approaches with trade-offs based on the actual codebase. Also check ~/.plannotator/plans/ for prior plan versions that may have already explored or rejected similar approaches.' },
41+
{ id: 'ensure-no-regression', emoji: '📉', text: 'Ensure no regression', color: 'amber', tip: 'Verify that this change will not break existing behavior. Identify what could regress and how to protect against it.' },
42+
{ id: 'out-of-scope', emoji: '🚫', text: 'Out of scope', color: 'red', tip: 'This is not part of the current task. Remove it and stay focused on what was actually requested.' },
43+
{ id: 'needs-tests', emoji: '🧪', text: 'Needs tests', color: 'blue' },
44+
{ id: 'nice-approach', emoji: '👍', text: 'Nice approach', color: 'green' },
4245
];
4346

4447
export function getQuickLabels(): QuickLabel[] {

0 commit comments

Comments
 (0)