improve a11y of fields, status page, and more (#505)

* improve a11y of fields, status page, and more

* tweak nav name

* fix community page and tweak text

* don't show pinned statuses heading unless there are pinned statuses
This commit is contained in:
Nolan Lawson 2018-08-28 06:44:36 -07:00 committed by GitHub
parent 46fa65f25a
commit 120f50919e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 62 additions and 28 deletions

View file

@ -1,12 +1,15 @@
<div class="dynamic-page-banner {icon ? 'dynamic-page-with-icon' : ''}"> <div class="dynamic-page-banner {icon ? 'dynamic-page-with-icon' : ''}"
role="navigation" aria-label="Page header"
>
{#if icon} {#if icon}
<svg class="dynamic-page-banner-svg"> <svg class="dynamic-page-banner-svg">
<use xlink:href={icon} /> <use xlink:href={icon} />
</svg> </svg>
{/if} {/if}
<h1 class="dynamic-page-title">{title}</h1> <h1 class="dynamic-page-title" aria-label={ariaTitle}>{title}</h1>
<button type="button" <button type="button"
class="dynamic-page-go-back" class="dynamic-page-go-back"
aria-label="Go back"
on:click="onGoBack(event)">Back</button> on:click="onGoBack(event)">Back</button>
</div> </div>
<style> <style>
@ -61,7 +64,8 @@
<script> <script>
export default { export default {
data: () => ({ data: () => ({
icon: void 0 icon: void 0,
ariaTitle: ''
}), }),
methods: { methods: {
onGoBack (e) { onGoBack (e) {

View file

@ -3,7 +3,7 @@
<svg class="page-list-item-svg"> <svg class="page-list-item-svg">
<use xlink:href={icon} /> <use xlink:href={icon} />
</svg> </svg>
<span aria-label="{label} {$pinnedPage === href ? 'Pinned page' : 'Unpinned page'}"> <span aria-label={ariaLabel}>
{label} {label}
</span> </span>
{#if pinnable} {#if pinnable}
@ -72,6 +72,15 @@
data: () => ({ data: () => ({
pinnable: false pinnable: false
}), }),
computed: {
ariaLabel: ({label, pinnable, $pinnedPage, href}) => {
let res = label
if (pinnable) {
res += ' (' + ($pinnedPage === href ? 'Pinned page' : 'Unpinned page') + ')'
}
return res
}
},
components: { components: {
IconButton IconButton
}, },

View file

@ -1,5 +1,5 @@
{#if realm === 'home'} {#if realm === 'home'}
<h1 class="sr-only">Compose toot</h1> <h1 class="sr-only">Compose status</h1>
{/if} {/if}
<div class="{computedClassName} {hideAndFadeIn}"> <div class="{computedClassName} {hideAndFadeIn}">
<ComposeAuthor /> <ComposeAuthor />

View file

@ -1,3 +1,4 @@
<h1 class="sr-only">Profile for {accountName}</h1>
<div class="account-profile {headerImageIsMissing ? 'header-image-is-missing' : ''}" <div class="account-profile {headerImageIsMissing ? 'header-image-is-missing' : ''}"
style="background-image: url({headerImage});"> style="background-image: url({headerImage});">
<div class="account-profile-grid-wrapper"> <div class="account-profile-grid-wrapper">
@ -79,7 +80,8 @@
store: () => store, store: () => store,
computed: { computed: {
headerImageIsMissing: ({ account }) => account.header.endsWith('missing.png'), headerImageIsMissing: ({ account }) => account.header.endsWith('missing.png'),
headerImage: ({ $autoplayGifs, account }) => $autoplayGifs ? account.header : account.header_static headerImage: ({ $autoplayGifs, account }) => $autoplayGifs ? account.header : account.header_static,
accountName: ({ account }) => (account && (account.display_name || account.username)) || ''
}, },
components: { components: {
AccountProfileHeader, AccountProfileHeader,

View file

@ -1,3 +1,4 @@
<h2 class="sr-only">Stats and more options</h2>
<div class="account-profile-details"> <div class="account-profile-details">
<div class="account-profile-details-item"> <div class="account-profile-details-item">
<span class="account-profile-details-item-title"> <span class="account-profile-details-item-title">

View file

@ -1,3 +1,4 @@
<h2 class="sr-only">Name and following</h2>
<div class="account-profile-avatar"> <div class="account-profile-avatar">
<Avatar {account} size="big" /> <Avatar {account} size="big" />
</div> </div>

View file

@ -1,11 +1,20 @@
{#if emojifiedFields.length} {#if emojifiedFields.length}
<h2 class="sr-only">Fields</h2>
<div class="account-profile-meta"> <div class="account-profile-meta">
<div class="account-profile-meta-border"></div> <div class="account-profile-meta-border"></div>
{#each emojifiedFields as field, i} {#each emojifiedFields as field, i}
<div class="account-profile-meta-cell account-profile-meta-name"> <div
id="account-profile-meta-name-{i}"
class="account-profile-meta-cell account-profile-meta-name"
role="term"
>
{field.name} {field.name}
</div> </div>
<div class="account-profile-meta-cell account-profile-meta-value"> <div
class="account-profile-meta-cell account-profile-meta-value"
role="definition"
aria-labelledby="account-profile-meta-name-{i}"
>
{@html field.value} {@html field.value}
</div> </div>
{/each} {/each}

View file

@ -1,3 +1,4 @@
<h2 class="sr-only">Description</h2>
<div class="account-profile-note"> <div class="account-profile-note">
{@html massagedNote} {@html massagedNote}
</div> </div>

View file

@ -217,9 +217,10 @@
} }
return originalAccountDisplayName return originalAccountDisplayName
}, },
ariaLabel: ({ originalAccountAccessibleName, originalStatus, visibility }) => ( ariaLabel: ({ originalAccountAccessibleName, originalStatus, visibility, isStatusInOwnThread }) => (
(visibility === 'direct' ? 'Direct message' : 'Status') + (visibility === 'direct' ? 'Direct message' : 'Status') +
` by ${originalAccountAccessibleName}` ` by ${originalAccountAccessibleName}` +
(isStatusInOwnThread ? ' (focused)' : '')
), ),
showHeader: ({ notification, status, timelineType }) => ( showHeader: ({ notification, status, timelineType }) => (
(notification && (notification.type === 'reblog' || notification.type === 'favourite')) || (notification && (notification.type === 'reblog' || notification.type === 'favourite')) ||

View file

@ -1,13 +1,16 @@
<div role="feed" aria-label="Pinned toots" class="pinned-statuses"> {#if pinnedStatuses.length }
{#each pinnedStatuses as status, index (status.id)} <h1 class="sr-only">Pinned statuses</h1>
<Status {status} <div role="feed" aria-label="Pinned statuses" class="pinned-statuses">
timelineType="pinned" {#each pinnedStatuses as status, index (status.id)}
timelineValue={accountId} <Status {status}
{index} timelineType="pinned"
length={pinnedStatuses.length} timelineValue={accountId}
/> {index}
{/each} length={pinnedStatuses.length}
</div> />
{/each}
</div>
{/if}
<script> <script>
import { store } from '../../_store/store' import { store } from '../../_store/store'
import Status from '../status/Status.html' import Status from '../status/Status.html'

View file

@ -109,20 +109,20 @@
}, },
label: ({ timeline, $currentInstance, timelineType, timelineValue }) => { label: ({ timeline, $currentInstance, timelineType, timelineValue }) => {
if (timelines[timeline]) { if (timelines[timeline]) {
return `${timelines[timeline].label} timeline for ${$currentInstance}` return `Statuses: ${timelines[timeline].label} timeline on ${$currentInstance}`
} }
switch (timelineType) { switch (timelineType) {
case 'tag': case 'tag':
return `#${timelineValue} timeline for ${$currentInstance}` return `Statuses: #${timelineValue} hashtag`
case 'status': case 'status':
return 'Status context' return `Statuses: thread`
case 'account': case 'account':
return `Account #${timelineValue} on ${$currentInstance}` return `Statuses: account timeline`
case 'list': case 'list':
return `List #${timelineValue} on ${$currentInstance}` return `Statuses: list`
case 'notifications': case 'notifications':
return `Notifications for ${$currentInstance}` return `Notifications on ${$currentInstance}`
} }
}, },
timelineType: ({ timeline }) => { timelineType: ({ timeline }) => {

View file

@ -1,6 +1,6 @@
{#if $isUserLoggedIn} {#if $isUserLoggedIn}
<TimelinePage timeline="account/{params.accountId}"> <TimelinePage timeline="account/{params.accountId}">
<DynamicPageBanner title="" /> <DynamicPageBanner title="" ariaTitle="Profile page for {accountName}"/>
{#if $currentAccountProfile && $currentVerifyCredentials} {#if $currentAccountProfile && $currentVerifyCredentials}
<AccountProfile account={$currentAccountProfile} <AccountProfile account={$currentAccountProfile}
relationship={$currentAccountRelationship} relationship={$currentAccountRelationship}
@ -42,6 +42,9 @@
}, },
shortProfileName: ({ $currentAccountProfile }) => { shortProfileName: ({ $currentAccountProfile }) => {
return ($currentAccountProfile && ('@' + $currentAccountProfile.username)) || '' return ($currentAccountProfile && ('@' + $currentAccountProfile.username)) || ''
},
accountName: ({ $currentAccountProfile }) => {
return ($currentAccountProfile && ($currentAccountProfile.display_name || $currentAccountProfile.username)) || ''
} }
}, },
components: { components: {

View file

@ -1,6 +1,6 @@
{#if $isUserLoggedIn} {#if $isUserLoggedIn}
<TimelinePage timeline="status/{params.statusId}"> <TimelinePage timeline="status/{params.statusId}">
<DynamicPageBanner title=""/> <DynamicPageBanner title="" ariaTitle="Status thread page" />
</TimelinePage> </TimelinePage>
{:else} {:else}
<HiddenFromSSR> <HiddenFromSSR>