diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 4e3dcb37c..a90e7a8d6 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -26,7 +26,9 @@ "game_has_no_executable": "Game has no executable selected", "sign_in": "Sign in", "friends": "Friends", - "need_help": "Need help?" + "need_help": "Need help?", + "aria_view_profile": "View profile", + "resize_sidebar": "Resize sidebar" }, "header": { "search": "Search games", @@ -36,7 +38,9 @@ "search_results": "Search results", "settings": "Settings", "version_available_install": "Version {{version}} available. Click here to restart and install.", - "version_available_download": "Version {{version}} available. Click here to download." + "version_available_download": "Version {{version}} available. Click here to download.", + "back": "Back", + "clear_search": "Clear search" }, "bottom_panel": { "no_downloads_in_progress": "No downloads in progress", @@ -141,6 +145,7 @@ "warning": "Warning:", "hydra_needs_to_remain_open": "for this download, Hydra needs to remain open util it's completed. If Hydra closes before completing, you will lose your progress.", "achievements": "Achievements", + "achievement": "Achievement", "achievements_count": "Achievements {{unlockedCount}}/{{achievementsCount}}", "cloud_save": "Cloud save", "cloud_save_description": "Save your progress in the cloud and continue playing on any device", @@ -394,6 +399,7 @@ }, "achievement": { "achievement_unlocked": "Achievement unlocked", + "achievement_locked": "Achievement locked", "user_achievements": "{{displayName}}'s Achievements", "your_achievements": "Your Achievements", "unlocked_at": "Unlocked at: {{date}}", @@ -405,7 +411,8 @@ "achievement_earn_points": "Earn {{points}} points with this achievement", "earned_points": "Earned points:", "available_points": "Available points:", - "how_to_earn_achievements_points": "How to earn achievements points?" + "how_to_earn_achievements_points": "How to earn achievements points?", + "aria_achievement_summary": "{{userDisplayName}} achievements for {{gameTitle}}, {{userAchievementCount}} unlocked of {{userTotalAchievementCount}}, {{percentage}} completed" }, "hydra_cloud": { "subscription_tour_title": "Hydra Cloud Subscription", diff --git a/src/locales/pt-BR/translation.json b/src/locales/pt-BR/translation.json index 2a80084f3..913a30540 100644 --- a/src/locales/pt-BR/translation.json +++ b/src/locales/pt-BR/translation.json @@ -26,7 +26,9 @@ "game_has_no_executable": "Jogo não possui executável selecionado", "sign_in": "Login", "friends": "Amigos", - "need_help": "Precisa de ajuda?" + "need_help": "Precisa de ajuda?", + "aria_view_profile": "Ver perfil", + "resize_sidebar": "Redimensionar barra lateral" }, "header": { "search": "Buscar jogos", @@ -36,7 +38,9 @@ "settings": "Ajustes", "home": "Início", "version_available_install": "Versão {{version}} disponível. Clique aqui para reiniciar e instalar.", - "version_available_download": "Versão {{version}} disponível. Clique aqui para fazer o download." + "version_available_download": "Versão {{version}} disponível. Clique aqui para fazer o download.", + "back": "Voltar", + "clear_search": "Limpar busca" }, "bottom_panel": { "no_downloads_in_progress": "Sem downloads em andamento", @@ -129,6 +133,7 @@ "warning": "Aviso:", "hydra_needs_to_remain_open": "para este download, o Hydra precisa ficar aberto até a conclusão. Caso o Hydra encerre antes da conclusão, perderá seu progresso.", "achievements": "Conquistas", + "achievement": "Conquista", "achievements_count": "Conquistas ({{unlockedCount}}/{{achievementsCount}})", "cloud_save": "Salvamento em nuvem", "cloud_save_description": "Mantenha seu progresso na nuvem e continue de onde parou em qualquer dispositivo", @@ -390,6 +395,7 @@ }, "achievement": { "achievement_unlocked": "Conquista desbloqueada", + "achievement_locked": "Conquista bloqueada", "your_achievements": "Suas Conquistas", "user_achievements": "Conquistas de {{displayName}}", "unlocked_at": "Desbloqueada em: {{date}}", @@ -401,7 +407,8 @@ "achievement_earn_points": "Ganhe {{points}} pontos com essa conquista", "earned_points": "Pontos ganhos:", "available_points": "Pontos disponíveis:", - "how_to_earn_achievements_points": "Como desbloquear pontos nas conquistas?" + "how_to_earn_achievements_points": "Como desbloquear pontos nas conquistas?", + "aria_achievement_summary": "Conquistas de {{userDisplayName}} em {{gameTitle}}, {{userAchievementCount}} desbloqueadas de {{userTotalAchievementCount}}, {{percentage}} concluídas" }, "hydra_cloud": { "subscription_tour_title": "Assinatura Hydra Cloud", diff --git a/src/renderer/src/components/header/header.tsx b/src/renderer/src/components/header/header.tsx index 3b5615f06..e97631549 100644 --- a/src/renderer/src/components/header/header.tsx +++ b/src/renderer/src/components/header/header.tsx @@ -58,6 +58,24 @@ export function Header() { navigate(-1); }; + useEffect(() => { + window.onkeydown = (event: KeyboardEvent) => { + const { key, ctrlKey } = event; + if (!isFocused && ctrlKey && key === "k") { + focusInput(); + } + + if (isFocused && key === "Escape" && inputRef.current) { + inputRef.current.blur(); + handleBlur(); + } + }; + + return () => { + window.onkeydown = null; + }; + }, [isFocused]); + const handleSearch = (value: string) => { dispatch(setFilters({ title: value })); @@ -88,6 +106,7 @@ export function Header() { })} onClick={handleBackButtonClick} disabled={location.key === "default"} + title={t("back")} > @@ -107,6 +126,8 @@ export function Header() { type="button" className={styles.actionButton} onClick={focusInput} + tabIndex={-1} + title={t("search")} > @@ -128,6 +149,7 @@ export function Header() { type="button" onClick={() => dispatch(setFilters({ title: "" }))} className={styles.actionButton} + title={t("clear_search")} > diff --git a/src/renderer/src/components/sidebar/sidebar-profile.tsx b/src/renderer/src/components/sidebar/sidebar-profile.tsx index 49e56ab78..af8da63c2 100644 --- a/src/renderer/src/components/sidebar/sidebar-profile.tsx +++ b/src/renderer/src/components/sidebar/sidebar-profile.tsx @@ -89,6 +89,7 @@ export function SidebarProfile() { type="button" className={styles.profileButton} onClick={handleProfileClick} + aria-label={t("aria_view_profile")} >
= ( + event + ) => { + const { key } = event; + + if (key === "ArrowRight") { + setSidebarWidth((prevWidth) => + prevWidth < SIDEBAR_INITIAL_WIDTH + ? SIDEBAR_INITIAL_WIDTH + : SIDEBAR_MAX_WIDTH + ); + } else if (key === "ArrowLeft") { + setSidebarWidth((prevWidth) => + prevWidth > SIDEBAR_INITIAL_WIDTH + ? SIDEBAR_INITIAL_WIDTH + : SIDEBAR_MIN_WIDTH + ); + } + }; + const handleFilter: React.ChangeEventHandler = (event) => { setFilteredLibrary( sortedLibrary.filter((game) => @@ -231,6 +251,7 @@ export function Sidebar() { type="button" className={styles.menuItemButton} onClick={(event) => handleSidebarGameClick(event, game)} + aria-label={game.title} > {game.iconUrl ? ( ); diff --git a/src/renderer/src/pages/achievements/achievements-content.tsx b/src/renderer/src/pages/achievements/achievements-content.tsx index e7d47f34a..3270e32f9 100644 --- a/src/renderer/src/pages/achievements/achievements-content.tsx +++ b/src/renderer/src/pages/achievements/achievements-content.tsx @@ -15,6 +15,7 @@ import { average } from "color.js"; import Color from "color"; import { Link } from "@renderer/components"; import { ComparedAchievementList } from "./compared-achievement-list"; +import { TFunction } from "i18next/typescript/t"; import * as styles from "./achievements.css"; import { AchievementList } from "./achievement-list"; import { AchievementPanel } from "./achievement-panel"; @@ -39,9 +40,35 @@ interface AchievementSummaryProps { isComparison?: boolean; } +const ariaLabelSummary = ( + t: TFunction, + gameTitle: string, + user: UserInfo +): string => { + return t("aria_achievement_summary", { + userDisplayName: user.displayName, + gameTitle: gameTitle, + userAchievementCount: user.unlockedAchievementCount, + userTotalAchievementCount: user.totalAchievementCount, + percentage: formatDownloadProgress( + user.unlockedAchievementCount / user.totalAchievementCount + ), + }); +}; + +const ariaLabelAchievement = ( + t: TFunction, + achievement: UserAchievement +): string => { + return `${ + achievement.unlocked ? t("achievement_unlocked") : t("achievement_locked") + }, ${achievement.displayName}, ${achievement.description}`; +}; + function AchievementSummary({ user, isComparison }: AchievementSummaryProps) { const { t } = useTranslation("achievement"); const { userDetails, hasActiveSubscription } = useUserDetails(); + const { handleClickOpenCheckout, gameTitle } = useContext(gameDetailsContext); const { showHydraCloudModal } = useSubscription(); const getProfileImage = ( @@ -124,6 +151,8 @@ function AchievementSummary({ user, isComparison }: AchievementSummaryProps) { alignItems: "center", padding: `${SPACING_UNIT}px`, }} + role="region" + aria-label={ariaLabelSummary(t, gameTitle, user)} > {getProfileImage(user)}
@@ -153,7 +153,7 @@ export function GallerySlider() { direction: "right", })} aria-label={t("next_screenshot")} - tabIndex={0} + tabIndex={-1} > @@ -169,6 +169,7 @@ export function GallerySlider() { })} onClick={() => setMediaIndex(i)} aria-label={t("open_screenshot", { number: i + 1 })} + onFocus={() => setMediaIndex(i)} >