Skip to content

Commit 7dc102f

Browse files
committed
cleanup accessbility
;
1 parent 5100085 commit 7dc102f

File tree

3 files changed

+93
-28
lines changed

3 files changed

+93
-28
lines changed

apps/dashboard/components/charts/metrics-chart-with-annotations.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,21 @@ export function MetricsChartWithAnnotations({
115115
loading: 'Creating annotation...',
116116
success: () => {
117117
refetchAnnotations();
118-
return 'Annotation created successfully';
118+
return 'Annotation created successfully! 🎉';
119119
},
120120
error: (err) => {
121121
console.error('Failed to create annotation:', err);
122-
return err?.message || 'Failed to create annotation';
122+
const errorMessage = err?.message || 'Failed to create annotation';
123+
toast.error(`Failed to create annotation: ${errorMessage}`);
124+
return errorMessage;
123125
},
124126
});
125127

126-
await promise;
128+
try {
129+
await promise;
130+
} catch (error) {
131+
console.error('Annotation creation failed:', error);
132+
}
127133
};
128134

129135
const handleEditAnnotation = (annotation: Annotation) => {

apps/dashboard/components/charts/metrics-chart.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,14 @@ export function MetricsChart({
333333
</div>
334334
</div>
335335
)}
336+
337+
{!refAreaLeft && annotations.length === 0 && (
338+
<div className="absolute top-4 right-4 z-10">
339+
<div className="bg-muted/80 backdrop-blur-sm border border-border/50 px-3 py-2 rounded-lg text-xs text-muted-foreground shadow-sm">
340+
💡 Drag on chart to create annotations
341+
</div>
342+
</div>
343+
)}
336344
<ResponsiveContainer height="100%" width="100%">
337345
<ComposedChart
338346
data={chartData}

apps/dashboard/components/charts/range-selection-popup.tsx

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
EyeIcon,
1111
EyeSlashIcon,
1212
} from '@phosphor-icons/react';
13-
import { useState } from 'react';
13+
import { useState, useEffect } from 'react';
1414
import { Button } from '@/components/ui/button';
1515
import {
1616
Card,
@@ -72,6 +72,29 @@ export function RangeSelectionPopup({
7272
const [selectedColor, setSelectedColor] = useState<string>(DEFAULT_ANNOTATION_VALUES.color);
7373
const [isPublic, setIsPublic] = useState<boolean>(DEFAULT_ANNOTATION_VALUES.isPublic);
7474
const [isSubmitting, setIsSubmitting] = useState(false);
75+
const [validationErrors, setValidationErrors] = useState<string[]>([]);
76+
77+
useEffect(() => {
78+
if (!isOpen) return;
79+
80+
const handleKeyDown = (e: KeyboardEvent) => {
81+
if (e.key === 'Escape') {
82+
onClose();
83+
} else if (e.key === 'Enter' && e.ctrlKey && showAnnotationForm) {
84+
e.preventDefault();
85+
handleCreateAnnotation();
86+
} else if (e.key === 'z' && e.ctrlKey && !showAnnotationForm) {
87+
e.preventDefault();
88+
handleZoom();
89+
} else if (e.key === 'a' && e.ctrlKey && !showAnnotationForm) {
90+
e.preventDefault();
91+
setShowAnnotationForm(true);
92+
}
93+
};
94+
95+
document.addEventListener('keydown', handleKeyDown);
96+
return () => document.removeEventListener('keydown', handleKeyDown);
97+
}, [isOpen, showAnnotationForm]);
7598

7699
const handleZoom = () => {
77100
onZoom(dateRange);
@@ -90,10 +113,11 @@ export function RangeSelectionPopup({
90113

91114
const validation = validateAnnotationForm(formData);
92115
if (!validation.isValid) {
93-
console.error('Validation errors:', validation.errors);
116+
setValidationErrors(validation.errors);
94117
return;
95118
}
96119

120+
setValidationErrors([]);
97121
setIsSubmitting(true);
98122
try {
99123
await onCreateAnnotation({
@@ -133,18 +157,23 @@ export function RangeSelectionPopup({
133157
return (
134158
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/20 backdrop-blur-sm">
135159
<div className="mx-4 w-full max-w-md">
136-
<Card className="shadow-2xl border-2 bg-card/95 backdrop-blur-sm">
160+
<Card
161+
className="shadow-2xl border-2 bg-card/95 backdrop-blur-sm"
162+
role="dialog"
163+
aria-labelledby="range-selection-title"
164+
aria-describedby="range-selection-description"
165+
>
137166
<CardHeader className="pb-4">
138167
<div className="flex items-center justify-between">
139168
<div className="flex items-center gap-3">
140169
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-primary/10">
141170
<CalendarIcon className="h-5 w-5 text-primary" />
142171
</div>
143172
<div>
144-
<CardTitle className="text-xl">
173+
<CardTitle id="range-selection-title" className="text-xl">
145174
{showAnnotationForm ? 'Add Annotation' : 'Range Selected'}
146175
</CardTitle>
147-
<CardDescription className="text-sm">
176+
<CardDescription id="range-selection-description" className="text-sm">
148177
{dateRange.startDate.toLocaleDateString('en-US', {
149178
month: 'short',
150179
day: 'numeric'
@@ -176,6 +205,7 @@ export function RangeSelectionPopup({
176205
className="w-full h-auto py-4 flex items-center justify-start gap-4"
177206
variant="outline"
178207
size="lg"
208+
aria-label="Zoom to range (Ctrl+Z)"
179209
>
180210
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-primary/10">
181211
<MagnifyingGlassIcon className="h-6 w-6 text-primary" />
@@ -186,13 +216,15 @@ export function RangeSelectionPopup({
186216
Focus on this period for detailed analysis
187217
</div>
188218
</div>
219+
<div className="text-xs text-muted-foreground">Ctrl+Z</div>
189220
</Button>
190221

191222
<Button
192223
onClick={() => setShowAnnotationForm(true)}
193224
className="w-full h-auto py-4 flex items-center justify-start gap-4"
194225
variant="outline"
195226
size="lg"
227+
aria-label="Add annotation (Ctrl+A)"
196228
>
197229
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-primary/10">
198230
<NoteIcon className="h-6 w-6 text-primary" />
@@ -203,6 +235,7 @@ export function RangeSelectionPopup({
203235
Mark this period with a note or label
204236
</div>
205237
</div>
238+
<div className="text-xs text-muted-foreground">Ctrl+A</div>
206239
</Button>
207240
</div>
208241
</>
@@ -235,11 +268,27 @@ export function RangeSelectionPopup({
235268
maxLength={DEFAULT_ANNOTATION_VALUES.maxTextLength}
236269
className="resize-none"
237270
disabled={isSubmitting}
271+
autoFocus
272+
aria-describedby="annotation-text-help annotation-text-count"
238273
/>
239274
<div className="flex justify-between items-center text-xs text-muted-foreground">
240-
<span>Keep it concise and descriptive</span>
241-
<span>{annotationText.length}/{DEFAULT_ANNOTATION_VALUES.maxTextLength}</span>
275+
<span id="annotation-text-help">Keep it concise and descriptive</span>
276+
<span id="annotation-text-count" className={annotationText.length > DEFAULT_ANNOTATION_VALUES.maxTextLength * 0.9 ? 'text-warning' : ''}>
277+
{annotationText.length}/{DEFAULT_ANNOTATION_VALUES.maxTextLength}
278+
</span>
242279
</div>
280+
281+
{/* Validation Errors */}
282+
{validationErrors.length > 0 && (
283+
<div className="space-y-1">
284+
{validationErrors.map((error, index) => (
285+
<div key={index} className="text-xs text-destructive flex items-center gap-1">
286+
<span className="text-destructive"></span>
287+
{error}
288+
</div>
289+
))}
290+
</div>
291+
)}
243292
</div>
244293

245294
{/* Tags */}
@@ -370,24 +419,26 @@ export function RangeSelectionPopup({
370419
>
371420
Cancel
372421
</Button>
373-
<Button
374-
onClick={handleCreateAnnotation}
375-
disabled={!annotationText.trim() || isSubmitting}
376-
className="flex-1"
377-
size="lg"
378-
>
379-
{isSubmitting ? (
380-
<>
381-
<div className="h-4 w-4 mr-2 animate-spin rounded-full border-2 border-current border-t-transparent" />
382-
Creating...
383-
</>
384-
) : (
385-
<>
386-
<NoteIcon className="h-4 w-4 mr-2" />
387-
Create Annotation
388-
</>
389-
)}
390-
</Button>
422+
<Button
423+
onClick={handleCreateAnnotation}
424+
disabled={!annotationText.trim() || isSubmitting}
425+
className="flex-1"
426+
size="lg"
427+
aria-label="Create annotation (Ctrl+Enter)"
428+
>
429+
{isSubmitting ? (
430+
<>
431+
<div className="h-4 w-4 mr-2 animate-spin rounded-full border-2 border-current border-t-transparent" />
432+
Creating...
433+
</>
434+
) : (
435+
<>
436+
<NoteIcon className="h-4 w-4 mr-2" />
437+
Create Annotation
438+
</>
439+
)}
440+
<span className="text-xs ml-2 opacity-60">Ctrl+Enter</span>
441+
</Button>
391442
</div>
392443
</div>
393444
</>

0 commit comments

Comments
 (0)