forked from cybrespace/pinafore
mvp for notifications
This commit is contained in:
parent
e19b60b9d2
commit
73ba72d58a
|
@ -1,7 +1,43 @@
|
||||||
<article class="notification-article"
|
{{#if notification.type === 'mention' || notification.type === 'reblog' || notification.type === 'favourite'}}
|
||||||
|
<Status :index :length :timelineType :timelineValue
|
||||||
|
status="{{notification.status}}"
|
||||||
|
:notification
|
||||||
|
on:recalculateHeight
|
||||||
|
/>
|
||||||
|
{{else}}
|
||||||
|
<article class="notification-article"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
aria-posinset="{{index}}" aria-setsize="{{length}}"
|
aria-posinset="{{index}}" aria-setsize="{{length}}"
|
||||||
on:recalculateHeight
|
>
|
||||||
>
|
<div class="follow-notification-offset">
|
||||||
Notification
|
<StatusHeader :status :notification />
|
||||||
</article>
|
</div>
|
||||||
|
</article>
|
||||||
|
{{/if}}
|
||||||
|
<style>
|
||||||
|
.notification-article {
|
||||||
|
width: 560px;
|
||||||
|
max-width: calc(100vw - 40px);
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-bottom: 1px solid var(--main-border);
|
||||||
|
}
|
||||||
|
.follow-notification-offset {
|
||||||
|
margin-left: 58px; /* offset for avatar, 48px + 10px */
|
||||||
|
}
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.notification-article {
|
||||||
|
padding: 10px 10px;
|
||||||
|
max-width: calc(100vw - 20px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import Status from '../status/Status.html'
|
||||||
|
import StatusHeader from '../status/StatusHeader.html'
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Status,
|
||||||
|
StatusHeader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -3,7 +3,7 @@
|
||||||
<PseudoVirtualListLazyItem
|
<PseudoVirtualListLazyItem
|
||||||
component="{{component}}"
|
component="{{component}}"
|
||||||
index="{{i}}"
|
index="{{i}}"
|
||||||
length="{{items.length}}"
|
length="{{wrappedItems.length}}"
|
||||||
makeProps="{{makeProps}}"
|
makeProps="{{makeProps}}"
|
||||||
key="{{wrappedItem.item}}"
|
key="{{wrappedItem.item}}"
|
||||||
intersectionObserver="{{intersectionObserver}}"
|
intersectionObserver="{{intersectionObserver}}"
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<:Component {component}
|
<:Component {component}
|
||||||
virtualProps="{{props}}"
|
virtualProps="{{props}}"
|
||||||
virtualIndex="{{index}}"
|
virtualIndex="{{index}}"
|
||||||
virtualLength="{length}}"
|
virtualLength="{{length}}"
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
:props
|
:props
|
||||||
:key
|
:key
|
||||||
:index
|
:index
|
||||||
|
:length
|
||||||
:scrollToThisItem
|
:scrollToThisItem
|
||||||
:intersectionObserver
|
:intersectionObserver
|
||||||
:isIntersecting
|
:isIntersecting
|
||||||
|
|
|
@ -2,16 +2,8 @@
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
aria-posinset="{{index}}" aria-setsize="{{length}}"
|
aria-posinset="{{index}}" aria-setsize="{{length}}"
|
||||||
on:recalculateHeight>
|
on:recalculateHeight>
|
||||||
{{#if status.reblog}}
|
{{#if (notification && (notification.type === 'reblog' || notification.type === 'favourite')) || status.reblog}}
|
||||||
<div class="status-boosted">
|
<StatusHeader :notification :status />
|
||||||
<svg>
|
|
||||||
<use xlink:href="#fa-retweet" />
|
|
||||||
</svg>
|
|
||||||
<span>
|
|
||||||
<a href="/accounts/{{status.account.id}}">{{status.account.username}}</a>
|
|
||||||
boosted
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div class="status-author">
|
<div class="status-author">
|
||||||
<a class="status-author-name" href="/accounts/{{originalAccount.id}}">
|
<a class="status-author-name" href="/accounts/{{originalAccount.id}}">
|
||||||
|
@ -80,9 +72,10 @@
|
||||||
width: 560px;
|
width: 560px;
|
||||||
max-width: calc(100vw - 40px);
|
max-width: calc(100vw - 40px);
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
|
border-bottom: 1px solid var(--main-border);
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
".............. status-boosted"
|
".............. status-header"
|
||||||
"status-sidebar status-author"
|
"status-sidebar status-author"
|
||||||
"status-sidebar status-spoiler"
|
"status-sidebar status-spoiler"
|
||||||
"status-sidebar status-spoiler-button"
|
"status-sidebar status-spoiler-button"
|
||||||
|
@ -90,7 +83,6 @@
|
||||||
"status-media status-media"
|
"status-media status-media"
|
||||||
".............. status-toolbar";
|
".............. status-toolbar";
|
||||||
grid-template-columns: 58px 1fr;
|
grid-template-columns: 58px 1fr;
|
||||||
border-bottom: 1px solid var(--main-border);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-article.status-direct {
|
.status-article.status-direct {
|
||||||
|
@ -200,27 +192,6 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-boosted span {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.status-boosted span, .status-boosted a, .status-boosted a:visited, .status-boosted a:hover) {
|
|
||||||
color: var(--deemphasized-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-boosted {
|
|
||||||
grid-area: status-boosted;
|
|
||||||
margin: 5px 10px 5px 5px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-boosted svg {
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
fill: var(--deemphasized-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-sensitive-media-container {
|
.status-sensitive-media-container {
|
||||||
grid-area: status-media;
|
grid-area: status-media;
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
|
@ -315,6 +286,7 @@
|
||||||
import Avatar from './Avatar.html'
|
import Avatar from './Avatar.html'
|
||||||
import Media from './Media.html'
|
import Media from './Media.html'
|
||||||
import Toolbar from './Toolbar.html'
|
import Toolbar from './Toolbar.html'
|
||||||
|
import StatusHeader from './StatusHeader.html'
|
||||||
import { mark, stop } from '../../_utils/marks'
|
import { mark, stop } from '../../_utils/marks'
|
||||||
import IntlRelativeFormat from 'intl-relativeformat'
|
import IntlRelativeFormat from 'intl-relativeformat'
|
||||||
import { replaceAll } from '../../_utils/strings'
|
import { replaceAll } from '../../_utils/strings'
|
||||||
|
@ -331,7 +303,8 @@
|
||||||
Avatar,
|
Avatar,
|
||||||
Media,
|
Media,
|
||||||
Toolbar,
|
Toolbar,
|
||||||
ExternalLink
|
ExternalLink,
|
||||||
|
StatusHeader
|
||||||
},
|
},
|
||||||
store: () => store,
|
store: () => store,
|
||||||
computed: {
|
computed: {
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
<div class="status-header">
|
||||||
|
<svg>
|
||||||
|
<use xlink:href="{{getIcon(notification, status)}}"/>
|
||||||
|
</svg>
|
||||||
|
<span>
|
||||||
|
<a href="/accounts/{{getAccount(notification, status).id}}">
|
||||||
|
{{getAccount(notification, status).display_name || ('@' + getAccount(notification, status).username)}}
|
||||||
|
</a>
|
||||||
|
{{#if notification && notification.type === 'reblog'}}
|
||||||
|
boosted your status
|
||||||
|
{{elseif notification && notification.type === 'favourite'}}
|
||||||
|
favorited your status
|
||||||
|
{{elseif notification && notification.type === 'follow'}}
|
||||||
|
followed you
|
||||||
|
{{elseif status && status.reblog}}
|
||||||
|
boosted
|
||||||
|
{{/if}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.status-header span {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.status-header span, .status-header a, .status-header a:visited, .status-header a:hover) {
|
||||||
|
color: var(--deemphasized-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-header {
|
||||||
|
grid-area: status-header;
|
||||||
|
margin: 5px 10px 5px 5px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-header svg {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
fill: var(--deemphasized-text-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
helpers: {
|
||||||
|
getIcon(notification, status) {
|
||||||
|
if ((notification && notification.type === 'reblog') || (status && status.reblog)) {
|
||||||
|
return '#fa-retweet'
|
||||||
|
} else if (notification && notification.type === 'follow') {
|
||||||
|
return '#fa-user-plus'
|
||||||
|
}
|
||||||
|
return '#fa-star'
|
||||||
|
},
|
||||||
|
getAccount(notification, status) {
|
||||||
|
if (notification && notification.account) {
|
||||||
|
return notification.account
|
||||||
|
}
|
||||||
|
return status.account
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -5,7 +5,7 @@
|
||||||
<:Component {component}
|
<:Component {component}
|
||||||
virtualProps="{{props}}"
|
virtualProps="{{props}}"
|
||||||
virtualIndex="{{index}}"
|
virtualIndex="{{index}}"
|
||||||
virtualLength="{{numItems}}"
|
virtualLength="{{$length}}"
|
||||||
on:recalculateHeight="doRecalculateHeight()"/>
|
on:recalculateHeight="doRecalculateHeight()"/>
|
||||||
</div>
|
</div>
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -72,7 +72,7 @@ virtualListStore.compute('height',
|
||||||
return showFooter ? (heightWithoutFooter + footerHeight) : heightWithoutFooter
|
return showFooter ? (heightWithoutFooter + footerHeight) : heightWithoutFooter
|
||||||
})
|
})
|
||||||
|
|
||||||
virtualListStore.compute('numItems', ['items'], (items) => items.length)
|
virtualListStore.compute('length', ['items'], (items) => items ? items.length : 0)
|
||||||
|
|
||||||
virtualListStore.compute('allVisibleItemsHaveHeight',
|
virtualListStore.compute('allVisibleItemsHaveHeight',
|
||||||
['visibleItems', 'itemHeights'],
|
['visibleItems', 'itemHeights'],
|
||||||
|
|
Loading…
Reference in New Issue