fix: use radio buttons for pinning timelines (#1644)
* fix: use radio buttons for pinning timelines more work on #1633 * cleanup styles
This commit is contained in:
parent
568a3f51fe
commit
1b95499008
|
@ -5,12 +5,16 @@
|
||||||
{label}
|
{label}
|
||||||
</span>
|
</span>
|
||||||
{#if pinnable}
|
{#if pinnable}
|
||||||
<IconButton pressable="true"
|
<RadioGroupButton
|
||||||
pressed={$pinnedPage === href}
|
id="pinnables"
|
||||||
label="Pin timeline"
|
className="pinnable-button"
|
||||||
pressedLabel="Timeline pinned"
|
checked={$pinnedPage === href}
|
||||||
href="#fa-thumb-tack"
|
label="Pin {label}"
|
||||||
on:click="onPinClick(event)" />
|
index={pinIndex}
|
||||||
|
on:click="onPinClick(event)"
|
||||||
|
>
|
||||||
|
<SvgIcon className="pinnable-svg" href="#fa-thumb-tack" />
|
||||||
|
</RadioGroupButton>
|
||||||
{/if}
|
{/if}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -52,6 +56,42 @@
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: begin copypasta from IconButton.html */
|
||||||
|
|
||||||
|
:global(.pinnable-button) {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
padding: 6px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.pinnable-button .pinnable-svg) {
|
||||||
|
fill: var(--action-button-fill-color);
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.pinnable-button:hover .pinnable-svg) {
|
||||||
|
fill: var(--action-button-fill-color-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.pinnable-button:active .pinnable-svg) {
|
||||||
|
fill: var(--action-button-fill-color-active);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.pinnable-button.checked .pinnable-svg) {
|
||||||
|
fill: var(--action-button-fill-color-pressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.pinnable-button.checked:hover .pinnable-svg) {
|
||||||
|
fill: var(--action-button-fill-color-pressed-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.pinnable-button.checked:active .pinnable-svg) {
|
||||||
|
fill: var(--action-button-fill-color-pressed-active);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: end copypasta */
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
.page-list-item a {
|
.page-list-item a {
|
||||||
padding: 20px 10px;
|
padding: 20px 10px;
|
||||||
|
@ -77,8 +117,8 @@
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import { store } from '../../_store/store'
|
import { store } from '../../_store/store'
|
||||||
import IconButton from '../IconButton'
|
|
||||||
import SvgIcon from '../SvgIcon.html'
|
import SvgIcon from '../SvgIcon.html'
|
||||||
|
import RadioGroupButton from '../../_components/radio/RadioGroupButton.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
store: () => store,
|
store: () => store,
|
||||||
|
@ -95,8 +135,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
IconButton,
|
SvgIcon,
|
||||||
SvgIcon
|
RadioGroupButton
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onPinClick (e) {
|
onPinClick (e) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<!-- Modeled after https://www.w3.org/TR/2016/WD-wai-aria-practices-1.1-20160317/examples/radio/radio.html -->
|
<!-- Modeled after https://www.w3.org/TR/2016/WD-wai-aria-practices-1.1-20160317/examples/radio/radio.html -->
|
||||||
<div class="radio-group focus-fix {className}"
|
<div class="radio-group {className}"
|
||||||
role="radiogroup"
|
role="radiogroup"
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
aria-owns={ariaOwns}
|
aria-owns={ariaOwns}
|
||||||
|
@ -29,6 +29,8 @@
|
||||||
const newIndex = (len + (index + (key === 'ArrowUp' ? -1 : 1))) % len // increment/decrement and wrap around
|
const newIndex = (len + (index + (key === 'ArrowUp' ? -1 : 1))) % len // increment/decrement and wrap around
|
||||||
buttons[newIndex].focus()
|
buttons[newIndex].focus()
|
||||||
buttons[newIndex].click()
|
buttons[newIndex].click()
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<button id="radio-group-button-{id}-{index}"
|
<button id="radio-group-button-{id}-{index}"
|
||||||
class="radio-group-button {className}"
|
class="radio-group-button {checked ? 'checked' : 'not-checked'} {className}"
|
||||||
role="radio"
|
role="radio"
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
title={label}
|
title={label}
|
||||||
|
@ -8,6 +8,21 @@
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</button>
|
</button>
|
||||||
|
<style>
|
||||||
|
.radio-group-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: 0;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.radio-group-button:hover {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.radio-group-button:active {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
data: () => ({
|
data: () => ({
|
||||||
|
|
|
@ -1,50 +1,62 @@
|
||||||
{#if $isUserLoggedIn}
|
{#if $isUserLoggedIn}
|
||||||
<div class="community-page">
|
<div class="community-page">
|
||||||
|
|
||||||
<h2 class="community-header">
|
<RadioGroup
|
||||||
Timelines
|
id="pinnables"
|
||||||
</h2>
|
length={numPinnable}
|
||||||
|
label="Pinnable timelines">
|
||||||
<PageList label="Timelines">
|
|
||||||
<PageListItem href="/local"
|
|
||||||
label="Local Timeline"
|
|
||||||
icon="#fa-users"
|
|
||||||
pinnable="true"
|
|
||||||
/>
|
|
||||||
<PageListItem href="/federated"
|
|
||||||
label="Federated Timeline"
|
|
||||||
icon="#fa-globe"
|
|
||||||
pinnable="true"
|
|
||||||
/>
|
|
||||||
<PageListItem href="/favorites"
|
|
||||||
label="Favorites"
|
|
||||||
icon="#fa-star"
|
|
||||||
pinnable="true"
|
|
||||||
/>
|
|
||||||
<PageListItem href="/direct"
|
|
||||||
label="Direct messages"
|
|
||||||
icon="#fa-envelope"
|
|
||||||
pinnable="true"
|
|
||||||
/>
|
|
||||||
</PageList>
|
|
||||||
|
|
||||||
{#if $lists.length}
|
|
||||||
|
|
||||||
<h2 class="community-header">
|
<h2 class="community-header">
|
||||||
Lists
|
Timelines
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<PageList label="Lists">
|
<PageList label="Timelines">
|
||||||
{#each $lists as list}
|
<PageListItem href="/local"
|
||||||
<PageListItem href="/lists/{list.id}"
|
label="Local Timeline"
|
||||||
label={list.title}
|
icon="#fa-users"
|
||||||
icon="#fa-bars"
|
|
||||||
pinnable="true"
|
pinnable="true"
|
||||||
|
pinIndex={0}
|
||||||
|
/>
|
||||||
|
<PageListItem href="/federated"
|
||||||
|
label="Federated Timeline"
|
||||||
|
icon="#fa-globe"
|
||||||
|
pinnable="true"
|
||||||
|
pinIndex={1}
|
||||||
|
/>
|
||||||
|
<PageListItem href="/favorites"
|
||||||
|
label="Favorites"
|
||||||
|
icon="#fa-star"
|
||||||
|
pinnable="true"
|
||||||
|
pinIndex={2}
|
||||||
|
/>
|
||||||
|
<PageListItem href="/direct"
|
||||||
|
label="Direct messages"
|
||||||
|
icon="#fa-envelope"
|
||||||
|
pinnable="true"
|
||||||
|
pinIndex={3}
|
||||||
/>
|
/>
|
||||||
{/each}
|
|
||||||
</PageList>
|
</PageList>
|
||||||
|
|
||||||
{/if}
|
{#if listsLength}
|
||||||
|
|
||||||
|
<h2 class="community-header">
|
||||||
|
Lists
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<PageList label="Lists">
|
||||||
|
{#each $lists as list, i}
|
||||||
|
<PageListItem href="/lists/{list.id}"
|
||||||
|
label={list.title}
|
||||||
|
icon="#fa-bars"
|
||||||
|
pinnable="true"
|
||||||
|
pinIndex={4 + i}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</PageList>
|
||||||
|
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
</RadioGroup>
|
||||||
|
|
||||||
<h2 class="community-header">
|
<h2 class="community-header">
|
||||||
Instance settings
|
Instance settings
|
||||||
|
@ -108,6 +120,7 @@
|
||||||
import HiddenFromSSR from '../../_components/HiddenFromSSR'
|
import HiddenFromSSR from '../../_components/HiddenFromSSR'
|
||||||
import PageList from '../../_components/community/PageList.html'
|
import PageList from '../../_components/community/PageList.html'
|
||||||
import PageListItem from '../../_components/community/PageListItem.html'
|
import PageListItem from '../../_components/community/PageListItem.html'
|
||||||
|
import RadioGroup from '../../_components/radio/RadioGroup.html'
|
||||||
import { updateListsForInstance } from '../../_actions/lists'
|
import { updateListsForInstance } from '../../_actions/lists'
|
||||||
import { updateFollowRequestCountIfLockedAccount } from '../../_actions/followRequests'
|
import { updateFollowRequestCountIfLockedAccount } from '../../_actions/followRequests'
|
||||||
|
|
||||||
|
@ -126,13 +139,16 @@
|
||||||
FreeTextLayout,
|
FreeTextLayout,
|
||||||
HiddenFromSSR,
|
HiddenFromSSR,
|
||||||
PageList,
|
PageList,
|
||||||
PageListItem
|
PageListItem,
|
||||||
|
RadioGroup
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isLockedAccount: ({ $currentVerifyCredentials }) => $currentVerifyCredentials && $currentVerifyCredentials.locked,
|
isLockedAccount: ({ $currentVerifyCredentials }) => $currentVerifyCredentials && $currentVerifyCredentials.locked,
|
||||||
followRequestsLabel: ({ $hasFollowRequests, $numberOfFollowRequests }) => (
|
followRequestsLabel: ({ $hasFollowRequests, $numberOfFollowRequests }) => (
|
||||||
`Follow requests${$hasFollowRequests ? ` (${$numberOfFollowRequests})` : ''}`
|
`Follow requests${$hasFollowRequests ? ` (${$numberOfFollowRequests})` : ''}`
|
||||||
)
|
),
|
||||||
|
listsLength: ({ $lists }) => $lists ? $lists.length : 0,
|
||||||
|
numPinnable: ({ listsLength }) => listsLength + 4 // 4 because of local/federated/favs/direct
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
38
tests/spec/037-pin-timelines.js
Normal file
38
tests/spec/037-pin-timelines.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import {
|
||||||
|
communityNavButton, getUrl, goBack, reload
|
||||||
|
} from '../utils'
|
||||||
|
import { loginAsFoobar } from '../roles'
|
||||||
|
import { Selector as $ } from 'testcafe'
|
||||||
|
|
||||||
|
fixture`037-pin-timelines.js`
|
||||||
|
.page`http://localhost:4002`
|
||||||
|
|
||||||
|
test('Can pin a timeline', async t => {
|
||||||
|
await loginAsFoobar(t)
|
||||||
|
|
||||||
|
const pinLocal = $('button[aria-label="Pin Local Timeline"]')
|
||||||
|
const pinFederated = $('button[aria-label="Pin Federated Timeline"]')
|
||||||
|
const pinnedNav = $('.main-nav-li:nth-child(3)')
|
||||||
|
const pinnedNavLink = $('.main-nav-li:nth-child(3) a')
|
||||||
|
|
||||||
|
await t
|
||||||
|
.click(communityNavButton)
|
||||||
|
.expect(getUrl()).contains('/community')
|
||||||
|
.expect(pinLocal.getAttribute('aria-checked')).eql('true')
|
||||||
|
.expect(pinFederated.getAttribute('aria-checked')).eql('false')
|
||||||
|
.expect(pinnedNavLink.getAttribute('aria-label')).eql('Local')
|
||||||
|
.click(pinFederated)
|
||||||
|
.expect(pinLocal.getAttribute('aria-checked')).eql('false')
|
||||||
|
.expect(pinFederated.getAttribute('aria-checked')).eql('true')
|
||||||
|
.expect(pinnedNavLink.getAttribute('aria-label')).eql('Federated')
|
||||||
|
.click(pinnedNav)
|
||||||
|
.expect(getUrl()).contains('/federated')
|
||||||
|
await goBack()
|
||||||
|
await t
|
||||||
|
.expect(getUrl()).contains('/community')
|
||||||
|
await reload()
|
||||||
|
await t
|
||||||
|
.expect(getUrl()).contains('/community')
|
||||||
|
.expect(pinLocal.getAttribute('aria-checked')).eql('false')
|
||||||
|
.expect(pinFederated.getAttribute('aria-checked')).eql('true')
|
||||||
|
})
|
Loading…
Reference in a new issue