pinafore/routes/_components/compose/ComposeBox.html

189 lines
6.1 KiB
HTML
Raw Normal View History

{#if realm === 'home'}
<h1 class="sr-only">Compose status</h1>
{/if}
<div class="{computedClassName} {hideAndFadeIn}">
<ComposeAuthor />
{#if contentWarningShown}
2018-03-04 00:25:22 +00:00
<div class="compose-content-warning-wrapper"
transition:slide="{duration: 333}">
<ComposeContentWarning {realm} {contentWarning} />
2018-03-04 00:25:22 +00:00
</div>
{/if}
<ComposeInput {realm} {text} {autoFocus} on:postAction="doPostStatus()" />
<ComposeLengthGauge {length} {overLimit} />
<ComposeToolbar {realm} {postPrivacy} {media} {contentWarningShown} {text} />
<ComposeLengthIndicator {length} {overLimit} />
<ComposeMedia {realm} {media} />
2018-02-26 00:26:43 +00:00
</div>
<ComposeStickyButton {showSticky}
{overLimit}
{hideAndFadeIn}
on:postAction="doPostStatus()" />
{#if !hideBottomBorder}
<div class="compose-box-border-bottom {hideAndFadeIn}"></div>
{/if}
2018-02-26 00:26:43 +00:00
<style>
2018-02-27 05:54:21 +00:00
.compose-box {
2018-02-26 00:26:43 +00:00
border-radius: 4px;
2018-03-27 07:02:55 +00:00
padding: 20px 20px 0 20px;
2018-02-26 00:26:43 +00:00
display: grid;
align-items: flex-start;
grid-template-areas:
2018-03-03 23:44:43 +00:00
"avatar name handle handle"
"avatar cw cw cw"
"avatar input input input"
"avatar gauge gauge gauge"
"avatar toolbar toolbar length"
2018-03-27 07:02:55 +00:00
"avatar media media media";
grid-template-columns: min-content minmax(0, max-content) 1fr 1fr;
2018-02-26 00:26:43 +00:00
width: 560px;
max-width: calc(100vw - 40px);
}
2018-04-05 06:03:26 +00:00
.compose-box.direct-reply {
background-color: var(--status-direct-background);
}
2018-03-30 08:06:17 +00:00
.compose-box.slim-size {
2018-03-27 07:02:55 +00:00
width: 540px;
2018-03-28 16:05:22 +00:00
max-width: calc(100vw - 60px);
2018-03-27 07:02:55 +00:00
}
.compose-box-fade-in {
transition: opacity 0.2s linear; /* main page reveal */
}
2018-03-27 07:02:55 +00:00
.compose-box-border-bottom {
height: 1px;
background: var(--main-border);
width: 100%;
}
2018-03-04 00:25:22 +00:00
.compose-content-warning-wrapper {
grid-area: cw;
}
2018-02-26 00:26:43 +00:00
@media (max-width: 767px) {
2018-02-27 05:54:21 +00:00
.compose-box {
2018-03-27 07:02:55 +00:00
padding: 10px 10px 0 10px;
2018-02-26 00:26:43 +00:00
max-width: calc(100vw - 20px);
width: 580px;
}
2018-03-30 08:06:17 +00:00
.compose-box.slim-size {
2018-03-27 07:02:55 +00:00
width: 560px;
max-width: calc(100vw - 40px);
}
2018-02-26 00:26:43 +00:00
}
</style>
<script>
2018-02-27 05:50:03 +00:00
import ComposeToolbar from './ComposeToolbar.html'
import ComposeLengthGauge from './ComposeLengthGauge.html'
import ComposeLengthIndicator from './ComposeLengthIndicator.html'
2018-02-27 05:54:21 +00:00
import ComposeAuthor from './ComposeAuthor.html'
2018-02-27 06:22:56 +00:00
import ComposeInput from './ComposeInput.html'
import ComposeStickyButton from './ComposeStickyButton.html'
2018-03-02 05:21:49 +00:00
import ComposeMedia from './ComposeMedia.html'
2018-03-03 23:44:43 +00:00
import ComposeContentWarning from './ComposeContentWarning.html'
2018-03-03 22:51:48 +00:00
import { measureText } from '../../_utils/measureText'
import { POST_PRIVACY_OPTIONS } from '../../_static/statuses'
2018-03-03 22:51:48 +00:00
import { store } from '../../_store/store'
2018-03-04 00:25:22 +00:00
import { slide } from 'svelte-transitions'
2018-04-04 00:50:48 +00:00
import { postStatus, insertHandleForReply, setReplySpoiler, setReplyVisibility } from '../../_actions/compose'
import { classname } from '../../_utils/classname'
2018-02-26 01:21:17 +00:00
2018-02-26 00:26:43 +00:00
export default {
2018-04-20 04:38:01 +00:00
oncreate () {
let { realm, replySpoiler, replyVisibility } = this.get()
if (realm !== 'home' && realm !== 'dialog') {
2018-03-09 16:45:12 +00:00
// if this is a reply, populate the handle immediately
/* no await */ insertHandleForReply(realm)
2018-03-27 07:02:55 +00:00
}
2018-03-09 16:45:12 +00:00
if (replySpoiler) {
// default spoiler is same as the replied-to status
setReplySpoiler(realm, replySpoiler)
}
2018-04-04 00:50:48 +00:00
if (replyVisibility) {
// make sure the visibility is consistent with the replied-to status
setReplyVisibility(realm, replyVisibility)
}
2018-03-27 07:02:55 +00:00
},
2018-02-26 00:26:43 +00:00
components: {
2018-02-27 05:54:21 +00:00
ComposeAuthor,
2018-02-27 05:50:03 +00:00
ComposeToolbar,
ComposeLengthGauge,
2018-02-27 06:22:56 +00:00
ComposeLengthIndicator,
ComposeInput,
ComposeStickyButton,
2018-03-03 23:44:43 +00:00
ComposeMedia,
ComposeContentWarning
2018-03-03 22:51:48 +00:00
},
data: () => ({
size: void 0,
isReply: false,
autoFocus: false,
hideBottomBorder: false,
hidden: false
}),
2018-03-03 22:51:48 +00:00
store: () => store,
computed: {
computedClassName: ({ overLimit, realm, size, postPrivacyKey, isReply }) => (classname(
2018-04-20 17:36:05 +00:00
'compose-box',
overLimit && 'over-char-limit',
size === 'slim' && 'slim-size',
isReply && postPrivacyKey === 'direct' && 'direct-reply'
)),
hideAndFadeIn: ({ hidden }) => (classname(
2018-04-20 17:36:05 +00:00
'compose-box-fade-in',
hidden && 'hidden'
)),
showSticky: ({ realm }) => realm === 'home',
composeData: ({ $currentComposeData, realm }) => $currentComposeData[realm] || {},
text: ({ composeData }) => composeData.text || '',
media: ({ composeData }) => composeData.media || [],
postPrivacy: ({ postPrivacyKey }) => POST_PRIVACY_OPTIONS.find(_ => _.key === postPrivacyKey),
defaultPostPrivacyKey: ({ $currentVerifyCredentials }) => $currentVerifyCredentials.source.privacy,
postPrivacyKey: ({ composeData, defaultPostPrivacyKey }) => composeData.postPrivacy || defaultPostPrivacyKey,
textLength: ({ text }) => measureText(text),
contentWarningLength: ({ contentWarning }) => measureText(contentWarning),
length: ({ textLength, contentWarningLength, contentWarningShown }) => (
2018-04-20 17:36:05 +00:00
textLength + (contentWarningShown ? contentWarningLength : 0)
),
overLimit: ({ length, $maxStatusChars }) => length > $maxStatusChars,
contentWarningShown: ({ composeData }) => composeData.contentWarningShown,
contentWarning: ({ composeData }) => composeData.contentWarning || ''
2018-03-04 00:25:22 +00:00
},
transitions: {
slide
2018-03-05 00:27:15 +00:00
},
methods: {
2018-04-20 04:38:01 +00:00
doPostStatus () {
let {
text,
media,
postPrivacyKey,
contentWarning,
realm,
overLimit,
inReplyToUuid
} = this.get()
let sensitive = media.length && !!contentWarning
let mediaIds = media.map(_ => _.data.id)
let mediaDescriptions = media.map(_ => _.description)
let inReplyTo = (realm === 'home' || realm === 'dialog') ? null : realm
2018-03-08 02:04:20 +00:00
if (overLimit || (!text && !media.length)) {
return // do nothing if invalid
2018-03-27 07:02:55 +00:00
}
/* no await */
postStatus(realm, text, inReplyTo, mediaIds,
sensitive, contentWarning, postPrivacyKey,
mediaDescriptions, inReplyToUuid)
2018-03-05 00:27:15 +00:00
}
2018-02-26 00:26:43 +00:00
}
}
2018-02-26 08:24:28 +00:00
</script>