<article class="status-article {{getClasses(originalStatus, timelineType, isStatusInOwnThread)}}" tabindex="0" delegate-key="{{delegateKey}}" focus-key="{{delegateKey}}" aria-posinset="{{index}}" aria-setsize="{{length}}" aria-label="{{ariaLabel}}" on:recalculateHeight> {{#if showHeader}} <StatusHeader :notification :status :isStatusInNotification :timelineType /> {{/if}} <StatusAuthorName status="{{originalStatus}}" :isStatusInOwnThread :isStatusInNotification /> <StatusAuthorHandle status="{{originalStatus}}" :isStatusInNotification /> {{#if !isStatusInOwnThread}} <StatusRelativeDate status="{{originalStatus}}" :isStatusInNotification /> {{/if}} <StatusSidebar status="{{originalStatus}}" :isStatusInOwnThread /> {{#if originalStatus.spoiler_text}} <StatusSpoiler status="{{originalStatus}}" :isStatusInOwnThread :contextualStatusId :isStatusInNotification on:recalculateHeight /> {{/if}} {{#if !originalStatus.spoiler_text || spoilerShown}} <StatusContent status="{{originalStatus}}" :isStatusInOwnThread :isStatusInNotification /> {{/if}} {{#if originalStatus.media_attachments && originalStatus.media_attachments.length}} <StatusMediaAttachments status="{{originalStatus}}" :timelineType :timelineValue /> {{/if}} {{#if isStatusInOwnThread}} <StatusDetails status="{{originalStatus}}" /> {{/if}} <StatusToolbar status="{{originalStatus}}" :isStatusInOwnThread /> </article> <style> .status-article { cursor: pointer; max-width: calc(100vw - 40px); padding: 10px 20px; display: grid; grid-template-areas: "....... header header header" "sidebar author-name author-handle relative-date" "sidebar spoiler spoiler spoiler" "sidebar spoiler-btn spoiler-btn spoiler-btn" "sidebar content content content" "media media media media" "....... toolbar toolbar toolbar"; grid-template-columns: min-content minmax(0, max-content) 1fr min-content; } .status-article.status-in-timeline { width: 560px; border-bottom: 1px solid var(--main-border); } .status-article.status-direct { background-color: var(--status-direct-background); } .status-article.status-in-own-thread { grid-template-areas: "sidebar author-name" "sidebar author-handle" "spoiler spoiler" "spoiler-btn spoiler-btn" "content content" "media media" "details details" "toolbar toolbar"; grid-template-columns: min-content 1fr; } @media (max-width: 767px) { .status-article { padding: 10px 10px; max-width: calc(100vw - 20px); } .status-article.status-in-timeline { width: 580px; } } </style> <script> import StatusSidebar from './StatusSidebar.html' import StatusHeader from './StatusHeader.html' import StatusAuthorName from './StatusAuthorName.html' import StatusAuthorHandle from './StatusAuthorHandle.html' import StatusRelativeDate from './StatusRelativeDate.html' import StatusDetails from './StatusDetails.html' import StatusToolbar from './StatusToolbar.html' import StatusMediaAttachments from './StatusMediaAttachments.html' import StatusContent from './StatusContent.html' import StatusSpoiler from './StatusSpoiler.html' import { store } from '../../_store/store' import { goto } from 'sapper/runtime.js' import { registerClickDelegate, unregisterClickDelegate } from '../../_utils/delegate' import { classname } from '../../_utils/classname' export default { oncreate() { let delegateKey = this.get('delegateKey') if (!this.get('isStatusInOwnThread')) { // the whole <article> is clickable in this case registerClickDelegate(delegateKey, (e) => this.onClickOrKeydown(e)) } }, ondestroy() { let delegateKey = this.get('delegateKey') if (!this.get('isStatusInOwnThread')) { unregisterClickDelegate(delegateKey) } }, components: { StatusSidebar, StatusHeader, StatusAuthorName, StatusAuthorHandle, StatusRelativeDate, StatusDetails, StatusToolbar, StatusMediaAttachments, StatusContent, StatusSpoiler }, store: () => store, helpers: { getClasses(originalStatus, timelineType, isStatusInOwnThread) { return classname( originalStatus.visibility === 'direct' && 'status-direct', timelineType !== 'search' && 'status-in-timeline', isStatusInOwnThread && 'status-in-own-thread' ) } }, methods: { onClickOrKeydown(e) { let { type, keyCode } = e let { localName, parentElement } = e.target if ((type === 'click' || (type === 'keydown' && keyCode === 13)) && localName !== 'a' && localName !== 'button' && parentElement.localName !== 'a' && parentElement.localName !== 'button' && parentElement.parentElement.localName !== 'a' && parentElement.parentElement.localName !== 'button') { e.preventDefault() e.stopPropagation() goto(`/statuses/${this.get('statusId')}`) } } }, computed: { originalStatus: (status) => status.reblog ? status.reblog : status, statusId: (originalStatus) => originalStatus.id, delegateKey: (statusId) => `status-${statusId}`, contextualStatusId: ($currentInstance, timelineType, timelineValue, status, notification) => { return `${$currentInstance}/${timelineType}/${timelineValue}/${notification ? notification.id : ''}/${status.id}` }, originalAccount: (originalStatus) => originalStatus.account, isStatusInOwnThread: (timelineType, timelineValue, statusId) => { return (timelineType === 'status' || timelineType === 'reply') && timelineValue === statusId }, isStatusInNotification: (status, notification) => notification && notification.status && notification.type !== 'mention' && notification.status.id === status.id, spoilerShown: ($spoilersShown, contextualStatusId) => !!$spoilersShown[contextualStatusId], visibility: (originalStatus) => originalStatus.visibility, ariaLabel: (originalAccount, visibility) => { return (visibility === 'direct' ? 'Direct message' : 'Status') + ` by ${originalAccount.display_name || originalAccount.username}` }, showHeader: (notification, status, timelineType) => { return (notification && (notification.type === 'reblog' || notification.type === 'favourite')) || status.reblog || timelineType === 'pinned' } } } </script>