forked from cybrespace/pinafore
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:
parent
46fa65f25a
commit
120f50919e
|
@ -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}
|
||||
<svg class="dynamic-page-banner-svg">
|
||||
<use xlink:href={icon} />
|
||||
</svg>
|
||||
{/if}
|
||||
<h1 class="dynamic-page-title">{title}</h1>
|
||||
<h1 class="dynamic-page-title" aria-label={ariaTitle}>{title}</h1>
|
||||
<button type="button"
|
||||
class="dynamic-page-go-back"
|
||||
aria-label="Go back"
|
||||
on:click="onGoBack(event)">Back</button>
|
||||
</div>
|
||||
<style>
|
||||
|
@ -61,7 +64,8 @@
|
|||
<script>
|
||||
export default {
|
||||
data: () => ({
|
||||
icon: void 0
|
||||
icon: void 0,
|
||||
ariaTitle: ''
|
||||
}),
|
||||
methods: {
|
||||
onGoBack (e) {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<svg class="page-list-item-svg">
|
||||
<use xlink:href={icon} />
|
||||
</svg>
|
||||
<span aria-label="{label} {$pinnedPage === href ? 'Pinned page' : 'Unpinned page'}">
|
||||
<span aria-label={ariaLabel}>
|
||||
{label}
|
||||
</span>
|
||||
{#if pinnable}
|
||||
|
@ -72,6 +72,15 @@
|
|||
data: () => ({
|
||||
pinnable: false
|
||||
}),
|
||||
computed: {
|
||||
ariaLabel: ({label, pinnable, $pinnedPage, href}) => {
|
||||
let res = label
|
||||
if (pinnable) {
|
||||
res += ' (' + ($pinnedPage === href ? 'Pinned page' : 'Unpinned page') + ')'
|
||||
}
|
||||
return res
|
||||
}
|
||||
},
|
||||
components: {
|
||||
IconButton
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{#if realm === 'home'}
|
||||
<h1 class="sr-only">Compose toot</h1>
|
||||
<h1 class="sr-only">Compose status</h1>
|
||||
{/if}
|
||||
<div class="{computedClassName} {hideAndFadeIn}">
|
||||
<ComposeAuthor />
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<h1 class="sr-only">Profile for {accountName}</h1>
|
||||
<div class="account-profile {headerImageIsMissing ? 'header-image-is-missing' : ''}"
|
||||
style="background-image: url({headerImage});">
|
||||
<div class="account-profile-grid-wrapper">
|
||||
|
@ -79,7 +80,8 @@
|
|||
store: () => store,
|
||||
computed: {
|
||||
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: {
|
||||
AccountProfileHeader,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<h2 class="sr-only">Stats and more options</h2>
|
||||
<div class="account-profile-details">
|
||||
<div class="account-profile-details-item">
|
||||
<span class="account-profile-details-item-title">
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<h2 class="sr-only">Name and following</h2>
|
||||
<div class="account-profile-avatar">
|
||||
<Avatar {account} size="big" />
|
||||
</div>
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
{#if emojifiedFields.length}
|
||||
<h2 class="sr-only">Fields</h2>
|
||||
<div class="account-profile-meta">
|
||||
<div class="account-profile-meta-border"></div>
|
||||
{#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}
|
||||
</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}
|
||||
</div>
|
||||
{/each}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<h2 class="sr-only">Description</h2>
|
||||
<div class="account-profile-note">
|
||||
{@html massagedNote}
|
||||
</div>
|
||||
|
|
|
@ -217,9 +217,10 @@
|
|||
}
|
||||
return originalAccountDisplayName
|
||||
},
|
||||
ariaLabel: ({ originalAccountAccessibleName, originalStatus, visibility }) => (
|
||||
ariaLabel: ({ originalAccountAccessibleName, originalStatus, visibility, isStatusInOwnThread }) => (
|
||||
(visibility === 'direct' ? 'Direct message' : 'Status') +
|
||||
` by ${originalAccountAccessibleName}`
|
||||
` by ${originalAccountAccessibleName}` +
|
||||
(isStatusInOwnThread ? ' (focused)' : '')
|
||||
),
|
||||
showHeader: ({ notification, status, timelineType }) => (
|
||||
(notification && (notification.type === 'reblog' || notification.type === 'favourite')) ||
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
<div role="feed" aria-label="Pinned toots" class="pinned-statuses">
|
||||
{#each pinnedStatuses as status, index (status.id)}
|
||||
<Status {status}
|
||||
timelineType="pinned"
|
||||
timelineValue={accountId}
|
||||
{index}
|
||||
length={pinnedStatuses.length}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{#if pinnedStatuses.length }
|
||||
<h1 class="sr-only">Pinned statuses</h1>
|
||||
<div role="feed" aria-label="Pinned statuses" class="pinned-statuses">
|
||||
{#each pinnedStatuses as status, index (status.id)}
|
||||
<Status {status}
|
||||
timelineType="pinned"
|
||||
timelineValue={accountId}
|
||||
{index}
|
||||
length={pinnedStatuses.length}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<script>
|
||||
import { store } from '../../_store/store'
|
||||
import Status from '../status/Status.html'
|
||||
|
|
|
@ -109,20 +109,20 @@
|
|||
},
|
||||
label: ({ timeline, $currentInstance, timelineType, timelineValue }) => {
|
||||
if (timelines[timeline]) {
|
||||
return `${timelines[timeline].label} timeline for ${$currentInstance}`
|
||||
return `Statuses: ${timelines[timeline].label} timeline on ${$currentInstance}`
|
||||
}
|
||||
|
||||
switch (timelineType) {
|
||||
case 'tag':
|
||||
return `#${timelineValue} timeline for ${$currentInstance}`
|
||||
return `Statuses: #${timelineValue} hashtag`
|
||||
case 'status':
|
||||
return 'Status context'
|
||||
return `Statuses: thread`
|
||||
case 'account':
|
||||
return `Account #${timelineValue} on ${$currentInstance}`
|
||||
return `Statuses: account timeline`
|
||||
case 'list':
|
||||
return `List #${timelineValue} on ${$currentInstance}`
|
||||
return `Statuses: list`
|
||||
case 'notifications':
|
||||
return `Notifications for ${$currentInstance}`
|
||||
return `Notifications on ${$currentInstance}`
|
||||
}
|
||||
},
|
||||
timelineType: ({ timeline }) => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{#if $isUserLoggedIn}
|
||||
<TimelinePage timeline="account/{params.accountId}">
|
||||
<DynamicPageBanner title="" />
|
||||
<DynamicPageBanner title="" ariaTitle="Profile page for {accountName}"/>
|
||||
{#if $currentAccountProfile && $currentVerifyCredentials}
|
||||
<AccountProfile account={$currentAccountProfile}
|
||||
relationship={$currentAccountRelationship}
|
||||
|
@ -42,6 +42,9 @@
|
|||
},
|
||||
shortProfileName: ({ $currentAccountProfile }) => {
|
||||
return ($currentAccountProfile && ('@' + $currentAccountProfile.username)) || ''
|
||||
},
|
||||
accountName: ({ $currentAccountProfile }) => {
|
||||
return ($currentAccountProfile && ($currentAccountProfile.display_name || $currentAccountProfile.username)) || ''
|
||||
}
|
||||
},
|
||||
components: {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{#if $isUserLoggedIn}
|
||||
<TimelinePage timeline="status/{params.statusId}">
|
||||
<DynamicPageBanner title=""/>
|
||||
<DynamicPageBanner title="" ariaTitle="Status thread page" />
|
||||
</TimelinePage>
|
||||
{:else}
|
||||
<HiddenFromSSR>
|
||||
|
|
Loading…
Reference in New Issue