From 2c507a474dcf8ca9257d2375a8a696950b31363b Mon Sep 17 00:00:00 2001 From: Dessalines <tyhou13@gmx.com> Date: Tue, 9 Feb 2021 11:21:24 -0500 Subject: [PATCH] Adding more aria labels based on tota11y recs. #170 --- src/shared/components/comment-node.tsx | 69 +++++++++++++++++++-- src/shared/components/communities.tsx | 4 ++ src/shared/components/community.tsx | 2 +- src/shared/components/inbox.tsx | 2 +- src/shared/components/main.tsx | 2 +- src/shared/components/markdown-textarea.tsx | 6 ++ src/shared/components/navbar.tsx | 19 +++++- src/shared/components/post-form.tsx | 4 +- src/shared/components/post-listing.tsx | 65 +++++++++++++++++-- src/shared/components/search.tsx | 6 +- src/shared/components/user.tsx | 2 +- 11 files changed, 159 insertions(+), 22 deletions(-) diff --git a/src/shared/components/comment-node.tsx b/src/shared/components/comment-node.tsx index bf57a59..33e719e 100644 --- a/src/shared/components/comment-node.tsx +++ b/src/shared/components/comment-node.tsx @@ -204,7 +204,14 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { onClick={linkEvent(node, this.handleCommentUpvote)} data-tippy-content={this.pointsTippy} > - <span class="mr-1 font-weight-bold">{this.state.score}</span> + <span + class="mr-1 font-weight-bold" + aria-label={i18n.t('number_of_points', { + count: this.state.score, + })} + > + {this.state.score} + </span> </a> <span className="mr-1">â¢</span> <span> @@ -424,6 +431,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleModRemoveShow )} + aria-label={i18n.t('remove')} > {i18n.t('remove')} </button> @@ -434,6 +442,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleModRemoveSubmit )} + aria-label={i18n.t('restore')} > {i18n.t('restore')} </button> @@ -451,6 +460,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleModBanFromCommunityShow )} + aria-label={i18n.t('ban')} > {i18n.t('ban')} </button> @@ -461,6 +471,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleModBanFromCommunitySubmit )} + aria-label={i18n.t('unban')} > {i18n.t('unban')} </button> @@ -474,6 +485,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleShowConfirmAppointAsMod )} + aria-label={ + this.isMod + ? i18n.t('remove_as_mod') + : i18n.t('appoint_as_mod') + } > {this.isMod ? i18n.t('remove_as_mod') @@ -481,7 +497,10 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { </button> ) : ( <> - <button class="btn btn-link btn-animate text-muted"> + <button + class="btn btn-link btn-animate text-muted" + aria-label={i18n.t('are_you_sure')} + > {i18n.t('are_you_sure')} </button> <button @@ -490,6 +509,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleAddModToCommunity )} + aria-label={i18n.t('yes')} > {i18n.t('yes')} </button> @@ -499,6 +519,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleCancelConfirmAppointAsMod )} + aria-label={i18n.t('no')} > {i18n.t('no')} </button> @@ -517,12 +538,16 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleShowConfirmTransferCommunity )} + aria-label={i18n.t('transfer_community')} > {i18n.t('transfer_community')} </button> ) : ( <> - <button class="btn btn-link btn-animate text-muted"> + <button + class="btn btn-link btn-animate text-muted" + aria-label={i18n.t('are_you_sure')} + > {i18n.t('are_you_sure')} </button> <button @@ -531,6 +556,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleTransferCommunity )} + aria-label={i18n.t('yes')} > {i18n.t('yes')} </button> @@ -541,6 +567,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this .handleCancelShowConfirmTransferCommunity )} + aria-label={i18n.t('no')} > {i18n.t('no')} </button> @@ -557,6 +584,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleModBanShow )} + aria-label={i18n.t('ban_from_site')} > {i18n.t('ban_from_site')} </button> @@ -567,6 +595,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleModBanSubmit )} + aria-label={i18n.t('unban_from_site')} > {i18n.t('unban_from_site')} </button> @@ -580,6 +609,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleShowConfirmAppointAsAdmin )} + aria-label={ + this.isAdmin + ? i18n.t('remove_as_admin') + : i18n.t('appoint_as_admin') + } > {this.isAdmin ? i18n.t('remove_as_admin') @@ -596,6 +630,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleAddAdmin )} + aria-label={i18n.t('yes')} > {i18n.t('yes')} </button> @@ -605,6 +640,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleCancelConfirmAppointAsAdmin )} + aria-label={i18n.t('no')} > {i18n.t('no')} </button> @@ -623,12 +659,16 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleShowConfirmTransferSite )} + aria-label={i18n.t('transfer_site')} > {i18n.t('transfer_site')} </button> ) : ( <> - <button class="btn btn-link btn-animate text-muted"> + <button + class="btn btn-link btn-animate text-muted" + aria-label={i18n.t('are_you_sure')} + > {i18n.t('are_you_sure')} </button> <button @@ -637,6 +677,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleTransferSite )} + aria-label={i18n.t('yes')} > {i18n.t('yes')} </button> @@ -646,6 +687,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this, this.handleCancelShowConfirmTransferSite )} + aria-label={i18n.t('no')} > {i18n.t('no')} </button> @@ -667,14 +709,25 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { class="form-inline" onSubmit={linkEvent(this, this.handleModRemoveSubmit)} > + <label + class="sr-only" + htmlFor={`mod-remove-reason-${cv.comment.id}`} + > + {i18n.t('reason')} + </label> <input type="text" + id={`mod-remove-reason-${cv.comment.id}`} class="form-control mr-2" placeholder={i18n.t('reason')} value={this.state.removeReason} onInput={linkEvent(this, this.handleModRemoveReasonChange)} /> - <button type="submit" class="btn btn-secondary"> + <button + type="submit" + class="btn btn-secondary" + aria-label={i18n.t('remove_comment')} + > {i18n.t('remove_comment')} </button> </form> @@ -717,7 +770,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { {/* <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */} {/* </div> */} <div class="form-group row"> - <button type="submit" class="btn btn-secondary"> + <button + type="submit" + class="btn btn-secondary" + aria-label={i18n.t('ban')} + > {i18n.t('ban')} {cv.creator.name} </button> </div> diff --git a/src/shared/components/communities.tsx b/src/shared/components/communities.tsx index e90c09d..62814b7 100644 --- a/src/shared/components/communities.tsx +++ b/src/shared/components/communities.tsx @@ -199,6 +199,7 @@ export class Communities extends Component<any, CommunitiesState> { > <input type="text" + id="communities-search" class="form-control mr-2 mb-2" value={this.state.searchText} placeholder={`${i18n.t('search')}...`} @@ -206,6 +207,9 @@ export class Communities extends Component<any, CommunitiesState> { required minLength={3} /> + <label class="sr-only" htmlFor="communities-search"> + {i18n.t('search')} + </label> <button type="submit" class="btn btn-secondary mr-2 mb-2"> <span>{i18n.t('search')}</span> </button> diff --git a/src/shared/components/community.tsx b/src/shared/components/community.tsx index 86ac243..c16b143 100644 --- a/src/shared/components/community.tsx +++ b/src/shared/components/community.tsx @@ -351,7 +351,7 @@ export class Community extends Component<any, State> { rel="noopener" > <svg class="icon text-muted small"> - <use xlinkHref="#icon-rss">#</use> + <use xlinkHref="#icon-rss"></use> </svg> </a> </div> diff --git a/src/shared/components/inbox.tsx b/src/shared/components/inbox.tsx index ab0c312..e9f52e1 100644 --- a/src/shared/components/inbox.tsx +++ b/src/shared/components/inbox.tsx @@ -158,7 +158,7 @@ export class Inbox extends Component<any, InboxState> { rel="noopener" > <svg class="icon ml-2 text-muted small"> - <use xlinkHref="#icon-rss">#</use> + <use xlinkHref="#icon-rss"></use> </svg> </a> </small> diff --git a/src/shared/components/main.tsx b/src/shared/components/main.tsx index 2d4b7d7..de7bc4f 100644 --- a/src/shared/components/main.tsx +++ b/src/shared/components/main.tsx @@ -602,7 +602,7 @@ export class Main extends Component<any, MainState> { title="RSS" > <svg class="icon text-muted small"> - <use xlinkHref="#icon-rss">#</use> + <use xlinkHref="#icon-rss"></use> </svg> </a> )} diff --git a/src/shared/components/markdown-textarea.tsx b/src/shared/components/markdown-textarea.tsx index cffc432..fe34b20 100644 --- a/src/shared/components/markdown-textarea.tsx +++ b/src/shared/components/markdown-textarea.tsx @@ -138,6 +138,9 @@ export class MarkdownTextArea extends Component< /> )} </div> + <label class="sr-only" htmlFor={this.id}> + {i18n.t('body')} + </label> </div> <div class="row"> <div class="col-sm-12 d-flex flex-wrap"> @@ -180,6 +183,7 @@ export class MarkdownTextArea extends Component< <button class="btn btn-sm text-muted" data-tippy-content={i18n.t('bold')} + aria-label={i18n.t('bold')} onClick={linkEvent(this, this.handleInsertBold)} > <svg class="icon icon-inline"> @@ -189,6 +193,7 @@ export class MarkdownTextArea extends Component< <button class="btn btn-sm text-muted" data-tippy-content={i18n.t('italic')} + aria-label={i18n.t('italic')} onClick={linkEvent(this, this.handleInsertItalic)} > <svg class="icon icon-inline"> @@ -198,6 +203,7 @@ export class MarkdownTextArea extends Component< <button class="btn btn-sm text-muted" data-tippy-content={i18n.t('link')} + aria-label={i18n.t('link')} onClick={linkEvent(this, this.handleInsertLink)} > <svg class="icon icon-inline"> diff --git a/src/shared/components/navbar.tsx b/src/shared/components/navbar.tsx index b4d2cbe..dee3fc5 100644 --- a/src/shared/components/navbar.tsx +++ b/src/shared/components/navbar.tsx @@ -202,7 +202,12 @@ export class Navbar extends Component<NavbarProps, NavbarState> { <use xlinkHref="#icon-bell"></use> </svg> {this.state.unreadCount > 0 && ( - <span class="mx-1 badge badge-light"> + <span + class="mx-1 badge badge-light" + aria-label={`${this.state.unreadCount} ${i18n.t( + 'unread_messages' + )}`} + > {this.state.unreadCount} </span> )} @@ -288,6 +293,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> { onSubmit={linkEvent(this, this.handleSearchSubmit)} > <input + id="search-input" class={`form-control mr-0 search-input ${ this.state.toggleSearch ? 'show-input' : 'hide-input' }`} @@ -298,11 +304,15 @@ export class Navbar extends Component<NavbarProps, NavbarState> { placeholder={i18n.t('search')} onBlur={linkEvent(this, this.handleSearchBlur)} ></input> + <label class="sr-only" htmlFor="search-input"> + {i18n.t('search')} + </label> <button name="search-btn" onClick={linkEvent(this, this.handleSearchBtn)} class="px-1 btn btn-link" style="color: var(--gray)" + aria-label={i18n.t('search')} > <svg class="icon"> <use xlinkHref="#icon-search"></use> @@ -323,7 +333,12 @@ export class Navbar extends Component<NavbarProps, NavbarState> { <use xlinkHref="#icon-bell"></use> </svg> {this.state.unreadCount > 0 && ( - <span class="ml-1 badge badge-light"> + <span + class="ml-1 badge badge-light" + aria-label={`${this.state.unreadCount} ${i18n.t( + 'unread_messages' + )}`} + > {this.state.unreadCount} </span> )} diff --git a/src/shared/components/post-form.tsx b/src/shared/components/post-form.tsx index 553a6e6..4435f29 100644 --- a/src/shared/components/post-form.tsx +++ b/src/shared/components/post-form.tsx @@ -283,9 +283,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> { </div> <div class="form-group row"> - <label class="col-sm-2 col-form-label" htmlFor={this.id}> - {i18n.t('body')} - </label> + <label class="col-sm-2 col-form-label">{i18n.t('body')}</label> <div class="col-sm-10"> <MarkdownTextArea initialContent={this.state.postForm.body} diff --git a/src/shared/components/post-listing.tsx b/src/shared/components/post-listing.tsx index 2d0192b..1255b3d 100644 --- a/src/shared/components/post-listing.tsx +++ b/src/shared/components/post-listing.tsx @@ -681,6 +681,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { class="btn btn-link btn-animate text-muted py-0" onClick={linkEvent(this, this.handleEditClick)} data-tippy-content={i18n.t('edit')} + aria-label={i18n.t('edit')} > <svg class="icon icon-inline"> <use xlinkHref="#icon-edit"></use> @@ -692,6 +693,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> { data-tippy-content={ !post_view.post.deleted ? i18n.t('delete') : i18n.t('restore') } + aria-label={ + !post_view.post.deleted ? i18n.t('delete') : i18n.t('restore') + } > <svg class={`icon icon-inline ${ @@ -722,6 +726,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { class="btn btn-link btn-animate text-muted py-0" onClick={linkEvent(this, this.handleViewSource)} data-tippy-content={i18n.t('view_source')} + aria-label={i18n.t('view_source')} > <svg class={`icon icon-inline ${ @@ -740,6 +745,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> { data-tippy-content={ post_view.post.locked ? i18n.t('unlock') : i18n.t('lock') } + aria-label={ + post_view.post.locked ? i18n.t('unlock') : i18n.t('lock') + } > <svg class={`icon icon-inline ${ @@ -757,6 +765,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> { ? i18n.t('unsticky') : i18n.t('sticky') } + aria-label={ + post_view.post.stickied + ? i18n.t('unsticky') + : i18n.t('sticky') + } > <svg class={`icon icon-inline ${ @@ -774,6 +787,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { <button class="btn btn-link btn-animate text-muted py-0" onClick={linkEvent(this, this.handleModRemoveShow)} + aria-label={i18n.t('remove')} > {i18n.t('remove')} </button> @@ -781,6 +795,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { <button class="btn btn-link btn-animate text-muted py-0" onClick={linkEvent(this, this.handleModRemoveSubmit)} + aria-label={i18n.t('restore')} > {i18n.t('restore')} </button> @@ -795,6 +810,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { this, this.handleModBanFromCommunityShow )} + aria-label={i18n.t('ban')} > {i18n.t('ban')} </button> @@ -805,6 +821,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { this, this.handleModBanFromCommunitySubmit )} + aria-label={i18n.t('unban')} > {i18n.t('unban')} </button> @@ -814,6 +831,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> { <button class="btn btn-link btn-animate text-muted py-0" onClick={linkEvent(this, this.handleAddModToCommunity)} + aria-label={ + this.isMod + ? i18n.t('remove_as_mod') + : i18n.t('appoint_as_mod') + } > {this.isMod ? i18n.t('remove_as_mod') @@ -833,16 +855,21 @@ export class PostListing extends Component<PostListingProps, PostListingState> { this, this.handleShowConfirmTransferCommunity )} + aria-label={i18n.t('transfer_community')} > {i18n.t('transfer_community')} </button> ) : ( <> - <button class="d-inline-block mr-1 btn btn-link btn-animate text-muted py-0"> + <button + class="d-inline-block mr-1 btn btn-link btn-animate text-muted py-0" + aria-label={i18n.t('are_you_sure')} + > {i18n.t('are_you_sure')} </button> <button class="btn btn-link btn-animate text-muted py-0 d-inline-block mr-1" + aria-label={i18n.t('yes')} onClick={linkEvent(this, this.handleTransferCommunity)} > {i18n.t('yes')} @@ -853,6 +880,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { this, this.handleCancelShowConfirmTransferCommunity )} + aria-label={i18n.t('no')} > {i18n.t('no')} </button> @@ -866,6 +894,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { <button class="btn btn-link btn-animate text-muted py-0" onClick={linkEvent(this, this.handleModBanShow)} + aria-label={i18n.t('ban_from_site')} > {i18n.t('ban_from_site')} </button> @@ -873,6 +902,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { <button class="btn btn-link btn-animate text-muted py-0" onClick={linkEvent(this, this.handleModBanSubmit)} + aria-label={i18n.t('unban_from_site')} > {i18n.t('unban_from_site')} </button> @@ -881,6 +911,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> { <button class="btn btn-link btn-animate text-muted py-0" onClick={linkEvent(this, this.handleAddAdmin)} + aria-label={ + this.isAdmin + ? i18n.t('remove_as_admin') + : i18n.t('appoint_as_admin') + } > {this.isAdmin ? i18n.t('remove_as_admin') @@ -899,17 +934,22 @@ export class PostListing extends Component<PostListingProps, PostListingState> { this, this.handleShowConfirmTransferSite )} + aria-label={i18n.t('transfer_site')} > {i18n.t('transfer_site')} </button> ) : ( <> - <button class="btn btn-link btn-animate text-muted py-0 d-inline-block mr-1"> + <button + class="btn btn-link btn-animate text-muted py-0 d-inline-block mr-1" + aria-label={i18n.t('are_you_sure')} + > {i18n.t('are_you_sure')} </button> <button class="btn btn-link btn-animate text-muted py-0 d-inline-block mr-1" onClick={linkEvent(this, this.handleTransferSite)} + aria-label={i18n.t('yes')} > {i18n.t('yes')} </button> @@ -919,6 +959,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { this, this.handleCancelShowConfirmTransferSite )} + aria-label={i18n.t('no')} > {i18n.t('no')} </button> @@ -940,14 +981,22 @@ export class PostListing extends Component<PostListingProps, PostListingState> { class="form-inline" onSubmit={linkEvent(this, this.handleModRemoveSubmit)} > + <label class="sr-only" htmlFor="post-listing-remove-reason"> + {i18n.t('reason')} + </label> <input type="text" + id="post-listing-remove-reason" class="form-control mr-2" placeholder={i18n.t('reason')} value={this.state.removeReason} onInput={linkEvent(this, this.handleModRemoveReasonChange)} /> - <button type="submit" class="btn btn-secondary"> + <button + type="submit" + class="btn btn-secondary" + aria-label={i18n.t('remove_post')} + > {i18n.t('remove_post')} </button> </form> @@ -955,12 +1004,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> { {this.state.showBanDialog && ( <form onSubmit={linkEvent(this, this.handleModBanBothSubmit)}> <div class="form-group row"> - <label class="col-form-label" htmlFor="post-listing-reason"> + <label class="col-form-label" htmlFor="post-listing-ban-reason"> {i18n.t('reason')} </label> <input type="text" - id="post-listing-reason" + id="post-listing-ban-reason" class="form-control mr-2" placeholder={i18n.t('reason')} value={this.state.banReason} @@ -987,7 +1036,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> { {/* <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */} {/* </div> */} <div class="form-group row"> - <button type="submit" class="btn btn-secondary"> + <button + type="submit" + class="btn btn-secondary" + aria-label={i18n.t('ban')} + > {i18n.t('ban')} {post.creator.name} </button> </div> diff --git a/src/shared/components/search.tsx b/src/shared/components/search.tsx index 1b61e3b..448b517 100644 --- a/src/shared/components/search.tsx +++ b/src/shared/components/search.tsx @@ -214,7 +214,11 @@ export class Search extends Component<any, SearchState> { required minLength={3} /> - <button type="submit" class="btn btn-secondary mr-2 mb-2"> + <button + type="submit" + class="btn btn-secondary mr-2 mb-2" + aria-label={i18n.t('search')} + > {this.state.loading ? ( <svg class="icon icon-spinner spin"> <use xlinkHref="#icon-spinner"></use> diff --git a/src/shared/components/user.tsx b/src/shared/components/user.tsx index 0dbe252..23faec9 100644 --- a/src/shared/components/user.tsx +++ b/src/shared/components/user.tsx @@ -394,7 +394,7 @@ export class User extends Component<any, UserState> { title="RSS" > <svg class="icon mx-2 text-muted small"> - <use xlinkHref="#icon-rss">#</use> + <use xlinkHref="#icon-rss"></use> </svg> </a> </div> -- 2.44.1