Polish screen-reader announcements to use app/folder display names

Co-authored-by: mroxso <24775431+mroxso@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-09-07 15:33:07 +00:00
committed by GitHub
parent 433168a705
commit 1d658f87dc
2 changed files with 32 additions and 20 deletions

View File

@@ -25,7 +25,7 @@ import { FolderDialog } from './FolderDialog';
import { FolderWindow } from './FolderWindow';
import { WindowLayer } from './WindowLayer';
import { useWindowManager } from '@/os/useWindowManager';
import { desktopApps } from '@/os/registry';
import { desktopApps, getApp } from '@/os/registry';
import { MENUBAR_HEIGHT } from '@/os/layout';
import { swapDesktopSlots, type DesktopSlot, type GridGeometry } from '@/os/iconLayout';
import { useIconLayout } from '@/os/useIconLayout';
@@ -108,15 +108,21 @@ export function Desktop() {
[folders],
);
// Screen-reader announcements name entries the way the user sees them.
const entryLabel = useCallback(
(id: string) => (id.startsWith(FOLDER_ID_PREFIX) ? folderTitle(id.slice(FOLDER_ID_PREFIX.length)) : getApp(id)?.title) ?? id,
[folderTitle],
);
const moveToFolder = useCallback((appId: string, folderId: string) => {
setAppFolder(appId, folderId);
setAnnouncement(`${appId} moved into folder ${folderTitle(folderId) ?? folderId}.`);
}, [setAppFolder, folderTitle]);
setAnnouncement(`${entryLabel(appId)} moved into folder ${folderTitle(folderId) ?? folderId}.`);
}, [setAppFolder, folderTitle, entryLabel]);
const removeFromFolder = useCallback((appId: string) => {
setAppFolder(appId, null);
setAnnouncement(`${appId} moved out of ${folderTitle(membership[appId]) ?? 'its folder'} to the desktop.`);
}, [setAppFolder, folderTitle, membership]);
setAnnouncement(`${entryLabel(appId)} moved out of ${folderTitle(membership[appId]) ?? 'its folder'} to the desktop.`);
}, [setAppFolder, folderTitle, membership, entryLabel]);
const deleteFolder = useCallback((folder: Folder) => {
removeFolder(folder.id);
@@ -133,7 +139,7 @@ export function Desktop() {
const id = createFolder(name);
if (folderDialog.appId) {
setAppFolder(folderDialog.appId, id);
setAnnouncement(`Folder ${name} created with ${folderDialog.appId} inside.`);
setAnnouncement(`Folder ${name} created with ${getApp(folderDialog.appId)?.title ?? folderDialog.appId} inside.`);
} else {
setAnnouncement(`Folder ${name} created.`);
}
@@ -159,8 +165,8 @@ export function Desktop() {
const move = useCallback((id: string, target: { col: number; row: number }) => {
setDesktop((current) => swapDesktopSlots(current, id, target));
const occupied = slots.find((slot) => slot.col === target.col && slot.row === target.row && slot.id !== id);
setAnnouncement(occupied ? `${id} swapped positions with ${occupied.id}.` : `${id} moved to column ${target.col + 1}, row ${target.row + 1}.`);
}, [setDesktop, slots]);
setAnnouncement(occupied ? `${entryLabel(id)} swapped positions with ${entryLabel(occupied.id)}.` : `${entryLabel(id)} moved to column ${target.col + 1}, row ${target.row + 1}.`);
}, [setDesktop, slots, entryLabel]);
const onPointerMove = useCallback((event: PointerEvent) => {
const active = pointerStart.current;
@@ -221,11 +227,11 @@ export function Desktop() {
if (picked === id) {
setPicked(null);
setPickedLayout(null);
setAnnouncement(`${id} dropped at column ${slot.col + 1}, row ${slot.row + 1}.`);
setAnnouncement(`${entryLabel(id)} dropped at column ${slot.col + 1}, row ${slot.row + 1}.`);
} else {
setPicked(id);
setPickedLayout(slots);
setAnnouncement(`${id} picked up. Use arrow keys to move, F to move into a folder, Enter to drop, Escape to cancel.`);
setAnnouncement(`${entryLabel(id)} picked up. Use arrow keys to move, F to move into a folder, Enter to drop, Escape to cancel.`);
}
return;
}
@@ -240,7 +246,7 @@ export function Desktop() {
setAnnouncement('No folders yet. Right-click an app and choose “New folder with it” to create one.');
return;
}
setAnnouncement(`Move ${id} into which folder? Press 1 to ${Math.min(9, folders.length)}: ${folders.slice(0, 9).map((folder, index) => `${index + 1} for ${folder.name}`).join(', ')}.`);
setAnnouncement(`Move ${entryLabel(id)} into which folder? Press 1 to ${Math.min(9, folders.length)}: ${folders.slice(0, 9).map((folder, index) => `${index + 1} for ${folder.name}`).join(', ')}.`);
return;
}
if (/^[1-9]$/.test(event.key) && !id.startsWith(FOLDER_ID_PREFIX)) {

View File

@@ -227,14 +227,20 @@ function HomeScreen({ onOpen }: { onOpen: (id: string) => void }) {
[folders],
);
// Screen-reader announcements name entries the way the user sees them.
const entryLabel = useCallback(
(id: string) => (id.startsWith(FOLDER_ID_PREFIX) ? folderTitle(id.slice(FOLDER_ID_PREFIX.length)) : getApp(id)?.title) ?? id,
[folderTitle],
);
const moveToFolder = (appId: string, folderId: string) => {
setAppFolder(appId, folderId);
setAnnouncement(`${appId} moved into folder ${folderTitle(folderId) ?? folderId}.`);
setAnnouncement(`${entryLabel(appId)} moved into folder ${folderTitle(folderId) ?? folderId}.`);
};
const removeFromFolder = (appId: string) => {
setAppFolder(appId, null);
setAnnouncement(`${appId} moved out of ${folderTitle(membership[appId]) ?? 'its folder'} to the home screen.`);
setAnnouncement(`${entryLabel(appId)} moved out of ${folderTitle(membership[appId]) ?? 'its folder'} to the home screen.`);
};
const deleteFolder = (folder: Folder) => {
@@ -264,8 +270,8 @@ function HomeScreen({ onOpen }: { onOpen: (id: string) => void }) {
return next;
});
const position = beforeId ? Math.max(1, layout.mobile.indexOf(beforeId) + 1) : layout.mobile.length;
setAnnouncement(`${id} moved to position ${position}.`);
}, [layout.mobile, setAnnouncement, setMobile]);
setAnnouncement(`${entryLabel(id)} moved to position ${position}.`);
}, [layout.mobile, setAnnouncement, setMobile, entryLabel]);
useEffect(() => {
const onMove = (event: PointerEvent) => {
@@ -321,11 +327,11 @@ function HomeScreen({ onOpen }: { onOpen: (id: string) => void }) {
if (picked === id) {
setPicked(null);
setPickedOrder(null);
setAnnouncement(`${id} dropped at position ${index + 1}.`);
setAnnouncement(`${entryLabel(id)} dropped at position ${index + 1}.`);
} else {
setPicked(id);
setPickedOrder(layout.mobile);
setAnnouncement(`${id} picked up. Use arrow keys to reorder, F to move into a folder, Enter to drop, Escape to cancel.`);
setAnnouncement(`${entryLabel(id)} picked up. Use arrow keys to reorder, F to move into a folder, Enter to drop, Escape to cancel.`);
}
return;
}
@@ -340,7 +346,7 @@ function HomeScreen({ onOpen }: { onOpen: (id: string) => void }) {
setAnnouncement('No folders yet. Create one with the button below the grid.');
return;
}
setAnnouncement(`Move ${id} into which folder? Press 1 to ${Math.min(9, folders.length)}: ${folders.slice(0, 9).map((folder, folderIndex) => `${folderIndex + 1} for ${folder.name}`).join(', ')}.`);
setAnnouncement(`Move ${entryLabel(id)} into which folder? Press 1 to ${Math.min(9, folders.length)}: ${folders.slice(0, 9).map((folder, folderIndex) => `${folderIndex + 1} for ${folder.name}`).join(', ')}.`);
return;
}
if (/^[1-9]$/.test(event.key) && !id.startsWith(FOLDER_ID_PREFIX)) {
@@ -364,7 +370,7 @@ function HomeScreen({ onOpen }: { onOpen: (id: string) => void }) {
next.splice(targetIndex, 0, id);
return next;
});
setAnnouncement(`${id} moved to position ${nextIndex + 1}.`);
setAnnouncement(`${entryLabel(id)} moved to position ${nextIndex + 1}.`);
};
const appContextMenu = (appId: string, title: string, currentFolderId: string | null) => (
@@ -599,7 +605,7 @@ function HomeScreen({ onOpen }: { onOpen: (id: string) => void }) {
const id = createFolder(name);
if (folderDialog.appId) {
setAppFolder(folderDialog.appId, id);
setAnnouncement(`Folder ${name} created with ${folderDialog.appId} inside.`);
setAnnouncement(`Folder ${name} created with ${getApp(folderDialog.appId)?.title ?? folderDialog.appId} inside.`);
} else {
setAnnouncement(`Folder ${name} created.`);
}