forked from Github/frigate
Accessibility features (#14518)
* Add screen reader aria labels to buttons and menu items * Fix sub_label score in search detail dialog
This commit is contained in:
@@ -737,6 +737,7 @@ function DetectionReview({
|
||||
<div className="col-span-full flex items-center justify-center">
|
||||
<Button
|
||||
className="text-white"
|
||||
aria-label="Mark these items as reviewed"
|
||||
variant="select"
|
||||
onClick={() => {
|
||||
setSelectedReviews([]);
|
||||
|
||||
@@ -144,6 +144,7 @@ export default function LiveBirdseyeView({
|
||||
{!fullscreen ? (
|
||||
<Button
|
||||
className={`flex items-center gap-2 rounded-lg ${isMobile ? "ml-2" : "ml-0"}`}
|
||||
aria-label="Go Back"
|
||||
size={isMobile ? "icon" : "sm"}
|
||||
onClick={() => navigate(-1)}
|
||||
>
|
||||
|
||||
@@ -352,6 +352,7 @@ export default function LiveCameraView({
|
||||
>
|
||||
<Button
|
||||
className={`flex items-center gap-2.5 rounded-lg`}
|
||||
aria-label="Go back"
|
||||
size="sm"
|
||||
onClick={() => navigate(-1)}
|
||||
>
|
||||
@@ -360,6 +361,7 @@ export default function LiveCameraView({
|
||||
</Button>
|
||||
<Button
|
||||
className="flex items-center gap-2.5 rounded-lg"
|
||||
aria-label="Show historical footage"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
navigate("review", {
|
||||
@@ -388,6 +390,7 @@ export default function LiveCameraView({
|
||||
{fullscreen && (
|
||||
<Button
|
||||
className="bg-gray-500 bg-gradient-to-br from-gray-400 to-gray-500 text-primary"
|
||||
aria-label="Go back"
|
||||
size="sm"
|
||||
onClick={() => navigate(-1)}
|
||||
>
|
||||
@@ -603,6 +606,7 @@ function PtzControlPanel({
|
||||
{ptz?.features?.includes("pt") && (
|
||||
<>
|
||||
<Button
|
||||
aria-label="Move PTZ camera to the left"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
sendPtz("MOVE_LEFT");
|
||||
@@ -617,6 +621,7 @@ function PtzControlPanel({
|
||||
<FaAngleLeft />
|
||||
</Button>
|
||||
<Button
|
||||
aria-label="Move PTZ camera up"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
sendPtz("MOVE_UP");
|
||||
@@ -631,6 +636,7 @@ function PtzControlPanel({
|
||||
<FaAngleUp />
|
||||
</Button>
|
||||
<Button
|
||||
aria-label="Move PTZ camera down"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
sendPtz("MOVE_DOWN");
|
||||
@@ -645,6 +651,7 @@ function PtzControlPanel({
|
||||
<FaAngleDown />
|
||||
</Button>
|
||||
<Button
|
||||
aria-label="Move PTZ camera to the right"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
sendPtz("MOVE_RIGHT");
|
||||
@@ -663,6 +670,7 @@ function PtzControlPanel({
|
||||
{ptz?.features?.includes("zoom") && (
|
||||
<>
|
||||
<Button
|
||||
aria-label="Zoom PTZ camera in"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
sendPtz("ZOOM_IN");
|
||||
@@ -677,6 +685,7 @@ function PtzControlPanel({
|
||||
<MdZoomIn />
|
||||
</Button>
|
||||
<Button
|
||||
aria-label="Zoom PTZ camera out"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
sendPtz("ZOOM_OUT");
|
||||
@@ -696,6 +705,7 @@ function PtzControlPanel({
|
||||
<>
|
||||
<Button
|
||||
className={`${clickOverlay ? "text-selected" : "text-primary"}`}
|
||||
aria-label="Click in the frame to center the PTZ camera"
|
||||
onClick={() => setClickOverlay(!clickOverlay)}
|
||||
>
|
||||
<TbViewfinder />
|
||||
@@ -705,7 +715,7 @@ function PtzControlPanel({
|
||||
{(ptz?.presets?.length ?? 0) > 0 && (
|
||||
<DropdownMenu modal={!isDesktop}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>
|
||||
<Button aria-label="PTZ camera presets">
|
||||
<BsThreeDotsVertical />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
@@ -717,6 +727,7 @@ function PtzControlPanel({
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
key={preset}
|
||||
aria-label={preset}
|
||||
className="cursor-pointer"
|
||||
onSelect={() => sendPtz(`preset_${preset}`)}
|
||||
>
|
||||
|
||||
@@ -240,6 +240,7 @@ export default function LiveDashboardView({
|
||||
? "bg-blue-900 bg-opacity-60 focus:bg-blue-900 focus:bg-opacity-60"
|
||||
: "bg-secondary"
|
||||
}`}
|
||||
aria-label="Use mobile grid layout"
|
||||
size="xs"
|
||||
onClick={() => setMobileLayout("grid")}
|
||||
>
|
||||
@@ -251,6 +252,7 @@ export default function LiveDashboardView({
|
||||
? "bg-blue-900 bg-opacity-60 focus:bg-blue-900 focus:bg-opacity-60"
|
||||
: "bg-secondary"
|
||||
}`}
|
||||
aria-label="Use mobile list layout"
|
||||
size="xs"
|
||||
onClick={() => setMobileLayout("list")}
|
||||
>
|
||||
@@ -267,6 +269,7 @@ export default function LiveDashboardView({
|
||||
? "bg-selected text-primary"
|
||||
: "bg-secondary text-secondary-foreground",
|
||||
)}
|
||||
aria-label="Enter layout editing mode"
|
||||
size="xs"
|
||||
onClick={() =>
|
||||
setIsEditMode((prevIsEditMode) => !prevIsEditMode)
|
||||
|
||||
@@ -380,6 +380,7 @@ export function RecordingView({
|
||||
<div className={cn("flex items-center gap-2")}>
|
||||
<Button
|
||||
className="flex items-center gap-2.5 rounded-lg"
|
||||
aria-label="Go back"
|
||||
size="sm"
|
||||
onClick={() => navigate(-1)}
|
||||
>
|
||||
@@ -388,6 +389,7 @@ export function RecordingView({
|
||||
</Button>
|
||||
<Button
|
||||
className="flex items-center gap-2.5 rounded-lg"
|
||||
aria-label="Go to the main camera live view"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
navigate(`/#${mainCamera}`);
|
||||
|
||||
@@ -95,6 +95,7 @@ export default function AuthenticationView() {
|
||||
</Heading>
|
||||
<Button
|
||||
className="flex items-center gap-1"
|
||||
aria-label="Add a new user"
|
||||
variant="default"
|
||||
onClick={() => {
|
||||
setShowCreate(true);
|
||||
@@ -114,6 +115,7 @@ export default function AuthenticationView() {
|
||||
<div className="flex flex-1 justify-end space-x-2">
|
||||
<Button
|
||||
className="flex items-center gap-1"
|
||||
aria-label="Update the user's password"
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
setShowSetPassword(true);
|
||||
@@ -125,6 +127,7 @@ export default function AuthenticationView() {
|
||||
</Button>
|
||||
<Button
|
||||
className="flex items-center gap-1"
|
||||
aria-label="Delete the user"
|
||||
variant="destructive"
|
||||
onClick={() => {
|
||||
setShowDelete(true);
|
||||
|
||||
@@ -475,6 +475,7 @@ export default function CameraSettingsView({
|
||||
<div className="flex w-full flex-row items-center gap-2 pt-2 md:w-[25%]">
|
||||
<Button
|
||||
className="flex flex-1"
|
||||
aria-label="Cancel"
|
||||
onClick={onCancel}
|
||||
type="button"
|
||||
>
|
||||
@@ -484,6 +485,7 @@ export default function CameraSettingsView({
|
||||
variant="select"
|
||||
disabled={isLoading}
|
||||
className="flex flex-1"
|
||||
aria-label="Save"
|
||||
type="submit"
|
||||
>
|
||||
{isLoading ? (
|
||||
|
||||
@@ -459,6 +459,7 @@ export default function MasksAndZonesView({
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="size-6 rounded-md bg-secondary-foreground p-1 text-background"
|
||||
aria-label="Add a new zone"
|
||||
onClick={() => {
|
||||
setEditPane("zone");
|
||||
handleNewPolygon("zone");
|
||||
@@ -527,6 +528,7 @@ export default function MasksAndZonesView({
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="size-6 rounded-md bg-secondary-foreground p-1 text-background"
|
||||
aria-label="Add a new motion mask"
|
||||
onClick={() => {
|
||||
setEditPane("motion_mask");
|
||||
handleNewPolygon("motion_mask");
|
||||
@@ -596,6 +598,7 @@ export default function MasksAndZonesView({
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="size-6 rounded-md bg-secondary-foreground p-1 text-background"
|
||||
aria-label="Add a new object mask"
|
||||
onClick={() => {
|
||||
setEditPane("object_mask");
|
||||
handleNewPolygon("object_mask");
|
||||
|
||||
@@ -284,13 +284,18 @@ export default function MotionTunerView({
|
||||
</div>
|
||||
<div className="flex flex-1 flex-col justify-end">
|
||||
<div className="flex flex-row gap-2 pt-5">
|
||||
<Button className="flex flex-1" onClick={onCancel}>
|
||||
<Button
|
||||
className="flex flex-1"
|
||||
aria-label="Reset"
|
||||
onClick={onCancel}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
disabled={!changedValue || isLoading}
|
||||
className="flex flex-1"
|
||||
aria-label="Save"
|
||||
onClick={saveToConfig}
|
||||
>
|
||||
{isLoading ? (
|
||||
|
||||
@@ -270,6 +270,7 @@ export default function NotificationView({
|
||||
<div className="flex w-full flex-row items-center gap-2 pt-2 md:w-[25%]">
|
||||
<Button
|
||||
className="flex flex-1"
|
||||
aria-label="Cancel"
|
||||
onClick={onCancel}
|
||||
type="button"
|
||||
>
|
||||
@@ -279,6 +280,7 @@ export default function NotificationView({
|
||||
variant="select"
|
||||
disabled={isLoading}
|
||||
className="flex flex-1"
|
||||
aria-label="Save"
|
||||
type="submit"
|
||||
>
|
||||
{isLoading ? (
|
||||
@@ -298,6 +300,7 @@ export default function NotificationView({
|
||||
<div className="space-y-3">
|
||||
<Separator className="my-2 flex bg-secondary" />
|
||||
<Button
|
||||
aria-label="Register or unregister notifications for this device"
|
||||
disabled={
|
||||
!config?.notifications.enabled || publicKey == undefined
|
||||
}
|
||||
|
||||
@@ -266,13 +266,14 @@ export default function SearchSettingsView({
|
||||
<Separator className="my-2 flex bg-secondary" />
|
||||
|
||||
<div className="flex w-full flex-row items-center gap-2 pt-2 md:w-[25%]">
|
||||
<Button className="flex flex-1" onClick={onCancel}>
|
||||
<Button className="flex flex-1" aria-label="Reset" onClick={onCancel}>
|
||||
Reset
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
disabled={!changedValue || isLoading}
|
||||
className="flex flex-1"
|
||||
aria-label="Save"
|
||||
onClick={saveToConfig}
|
||||
>
|
||||
{isLoading ? (
|
||||
|
||||
@@ -125,7 +125,12 @@ export default function UiSettingsView() {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button onClick={clearStoredLayouts}>Clear All Layouts</Button>
|
||||
<Button
|
||||
aria-label="Clear all saved layouts"
|
||||
onClick={clearStoredLayouts}
|
||||
>
|
||||
Clear All Layouts
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Separator className="my-2 flex bg-secondary" />
|
||||
|
||||
@@ -541,6 +541,7 @@ export default function GeneralMetrics({
|
||||
{canGetGpuInfo && (
|
||||
<Button
|
||||
className="cursor-pointer"
|
||||
aria-label="Hardware information"
|
||||
size="sm"
|
||||
onClick={() => setShowVainfo(true)}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user