694 lines
22 KiB
Vue
694 lines
22 KiB
Vue
<template>
|
|
<div class="new-toot">
|
|
<el-dialog
|
|
:title="$t('modals.new_toot.title')"
|
|
:model-value="newTootModal"
|
|
@update:model-value="newTootModal = $event"
|
|
:before-close="closeConfirm"
|
|
width="600px"
|
|
custom-class="new-toot-modal"
|
|
v-if="newTootModal"
|
|
>
|
|
<el-form v-on:submit.prevent="toot" role="form">
|
|
<Quote :message="quoteToMessage" :displayNameStyle="displayNameStyle" v-if="quoteToMessage !== null" ref="quoteRef"></Quote>
|
|
<div class="spoiler" v-if="showContentWarning" ref="spoilerRef">
|
|
<div class="el-input">
|
|
<input type="text" class="el-input__inner" :placeholder="$t('modals.new_toot.cw')" v-model="spoilerText" />
|
|
</div>
|
|
</div>
|
|
<Status
|
|
:modelValue="statusText"
|
|
@update:modelValue="statusText = $event"
|
|
:opened="newTootModal"
|
|
:fixCursorPos="hashtagInserting"
|
|
:height="statusHeight"
|
|
@paste="onPaste"
|
|
@toot="toot"
|
|
ref="statusRef"
|
|
v-if="newTootModal"
|
|
/>
|
|
</el-form>
|
|
<Poll
|
|
v-if="openPoll"
|
|
v-model:polls="polls"
|
|
v-model:expire="pollExpire"
|
|
@addPoll="addPoll"
|
|
@removePoll="removePoll"
|
|
ref="pollRef"
|
|
></Poll>
|
|
<div class="preview" ref="previewRef">
|
|
<div class="image-wrapper" v-for="media in attachedMedias" v-bind:key="media.id">
|
|
<img :src="media.preview_url" class="preview-image" />
|
|
<el-button type="text" @click="removeAttachment(media)" class="remove-image"><font-awesome-icon icon="circle-xmark" /></el-button>
|
|
<textarea
|
|
maxlength="420"
|
|
class="image-description"
|
|
:placeholder="$t('modals.new_toot.description')"
|
|
:value="mediaDescriptions[media.id]"
|
|
@input="updateDescription(media.id, $event.target.value)"
|
|
role="textbox"
|
|
contenteditable="true"
|
|
aria-multiline="true"
|
|
>
|
|
</textarea>
|
|
</div>
|
|
</div>
|
|
<template #footer>
|
|
<div class="dialog-footer">
|
|
<div class="upload-image">
|
|
<el-button size="default" type="text" @click="selectImage" :title="$t('modals.new_toot.footer.add_image')">
|
|
<font-awesome-icon icon="camera" />
|
|
</el-button>
|
|
<input name="image" type="file" class="image-input" ref="imageRef" @change="onChangeImage" />
|
|
</div>
|
|
<div class="poll">
|
|
<el-button size="default" type="text" @click="togglePollForm" :title="$t('modals.new_toot.footer.poll')">
|
|
<font-awesome-icon icon="square-poll-horizontal" />
|
|
</el-button>
|
|
</div>
|
|
<div class="privacy">
|
|
<el-dropdown trigger="click" @command="changeVisibility">
|
|
<el-button size="default" type="text" :title="$t('modals.new_toot.footer.change_visibility')">
|
|
<font-awesome-icon :icon="visibilityIcon" />
|
|
</el-button>
|
|
<template #dropdown>
|
|
<el-dropdown-menu>
|
|
<el-dropdown-item :command="visibilityList.Public.value">
|
|
<font-awesome-icon icon="globe" class="privacy-icon" />
|
|
{{ $t(visibilityList.Public.name) }}
|
|
</el-dropdown-item>
|
|
<el-dropdown-item :command="visibilityList.Unlisted.value">
|
|
<font-awesome-icon icon="unlock" class="privacy-icon" />
|
|
{{ $t(visibilityList.Unlisted.name) }}
|
|
</el-dropdown-item>
|
|
<el-dropdown-item :command="visibilityList.Private.value">
|
|
<font-awesome-icon icon="lock" class="privacy-icon" />
|
|
{{ $t(visibilityList.Private.name) }}
|
|
</el-dropdown-item>
|
|
<el-dropdown-item :command="visibilityList.Direct.value">
|
|
<font-awesome-icon icon="envelope" class="privacy-icon" size="sm" />
|
|
{{ $t(visibilityList.Direct.name) }}
|
|
</el-dropdown-item>
|
|
</el-dropdown-menu>
|
|
</template>
|
|
</el-dropdown>
|
|
</div>
|
|
<div class="sensitive" v-show="attachedMedias.length > 0">
|
|
<el-button
|
|
size="default"
|
|
type="text"
|
|
@click="changeSensitive"
|
|
:title="$t('modals.new_toot.footer.change_sensitive')"
|
|
:aria-pressed="sensitive"
|
|
>
|
|
<font-awesome-icon icon="eye-slash" v-show="!sensitive" />
|
|
<font-awesome-icon icon="eye" v-show="sensitive" />
|
|
</el-button>
|
|
</div>
|
|
<div class="content-warning">
|
|
<el-button
|
|
size="default"
|
|
type="text"
|
|
@click="toggleContentWarning()"
|
|
:title="$t('modals.new_toot.footer.add_cw')"
|
|
:class="showContentWarning ? '' : 'clickable'"
|
|
:aria-pressed="showContentWarning"
|
|
>
|
|
<font-awesome-icon icon="eye-slash" />
|
|
</el-button>
|
|
</div>
|
|
<div class="pined-hashtag">
|
|
<el-button
|
|
size="default"
|
|
type="text"
|
|
@click="pinedHashtag = !pinedHashtag"
|
|
:title="$t('modals.new_toot.footer.pined_hashtag')"
|
|
:class="pinedHashtag ? '' : 'clickable'"
|
|
:aria-pressed="pinedHashtag"
|
|
>
|
|
<font-awesome-icon icon="hashtag" />
|
|
</el-button>
|
|
</div>
|
|
<div class="info">
|
|
<img src="../../../assets/images/loading-spinner-wide.svg" v-show="loading" class="loading" />
|
|
<span class="text-count">{{ tootMax - statusText.length }}</span>
|
|
|
|
<el-button class="toot-action" @click="closeConfirm(close)">{{ $t('modals.new_toot.cancel') }}</el-button>
|
|
<el-button class="toot-action" type="primary" @click="toot" :loading="blockSubmit">{{ $t('modals.new_toot.toot') }}</el-button>
|
|
</div>
|
|
<div class="clearfix"></div>
|
|
</div>
|
|
</template>
|
|
<resize-observer @notify="handleResize" />
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { defineComponent, ref, reactive, computed, onMounted, ComponentPublicInstance, nextTick, onBeforeUnmount } from 'vue'
|
|
import { useI18next } from 'vue3-i18next'
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
import { Entity } from 'megalodon'
|
|
import { useStore } from '@/store'
|
|
import Visibility from '~/src/constants/visibility'
|
|
import Status from './NewToot/Status.vue'
|
|
import Poll from './NewToot/Poll.vue'
|
|
import Quote from './NewToot/Quote.vue'
|
|
import { NewTootTootLength, NewTootAttachLength, NewTootModalOpen, NewTootBlockSubmit, NewTootPollInvalid } from '@/errors/validations'
|
|
import { EventEmitter } from '@/components/event'
|
|
import { ACTION_TYPES, MUTATION_TYPES } from '@/store/TimelineSpace/Modals/NewToot'
|
|
|
|
export default defineComponent({
|
|
name: 'new-toot',
|
|
components: {
|
|
Status,
|
|
Poll,
|
|
Quote
|
|
},
|
|
setup() {
|
|
const space = 'TimelineSpace/Modals/NewToot'
|
|
const store = useStore()
|
|
const i18n = useI18next()
|
|
const visibilityList = Visibility
|
|
|
|
const enableResizing = ref<boolean>(true)
|
|
const statusText = ref<string>('')
|
|
const spoilerText = ref<string>('')
|
|
const showContentWarning = ref<boolean>(false)
|
|
const openPoll = ref<boolean>(false)
|
|
const polls = ref<Array<string>>([])
|
|
const pollExpire = reactive({
|
|
label: i18n.t('modals.new_toot.poll.expires.1_day'),
|
|
value: 3600 * 24
|
|
})
|
|
const statusHeight = ref<number>(240)
|
|
const previewRef = ref<HTMLElement>()
|
|
const imageRef = ref<HTMLInputElement>()
|
|
const pollRef = ref<ComponentPublicInstance>()
|
|
const spoilerRef = ref<HTMLElement>()
|
|
const quoteRef = ref<ComponentPublicInstance>()
|
|
const statusRef = ref<InstanceType<typeof Status>>()
|
|
|
|
const quoteToMessage = computed(() => store.state.TimelineSpace.Modals.NewToot.quoteToMessage)
|
|
const attachedMedias = computed(() => store.state.TimelineSpace.Modals.NewToot.attachedMedias)
|
|
const mediaDescriptions = computed(() => store.state.TimelineSpace.Modals.NewToot.mediaDescriptions)
|
|
const blockSubmit = computed(() => store.state.TimelineSpace.Modals.NewToot.blockSubmit)
|
|
const sensitive = computed(() => store.state.TimelineSpace.Modals.NewToot.sensitive)
|
|
const initialStatus = computed(() => store.state.TimelineSpace.Modals.NewToot.initialStatus)
|
|
const initialSpoiler = computed(() => store.state.TimelineSpace.Modals.NewToot.initialSpoiler)
|
|
const visibilityIcon = computed(() => {
|
|
switch (store.state.TimelineSpace.Modals.NewToot.visibility) {
|
|
case Visibility.Public.value:
|
|
return 'globe'
|
|
case Visibility.Unlisted.value:
|
|
return 'unlock'
|
|
case Visibility.Private.value:
|
|
return 'lock'
|
|
case Visibility.Direct.value:
|
|
return 'envelope'
|
|
default:
|
|
return 'globe'
|
|
}
|
|
})
|
|
const loading = computed(() => store.state.TimelineSpace.Modals.NewToot.loading)
|
|
const tootMax = computed(() => store.state.TimelineSpace.tootMax)
|
|
const displayNameStyle = computed(() => store.state.App.displayNameStyle)
|
|
const hashtagInserting = computed(() => store.getters[`${space}/hashtagInserting`])
|
|
const newTootModal = computed({
|
|
get: () => store.state.TimelineSpace.Modals.NewToot.modalOpen,
|
|
set: (value: boolean) => {
|
|
if (value) {
|
|
store.dispatch(`${space}/${ACTION_TYPES.OPEN_MODAL}`)
|
|
} else {
|
|
store.dispatch(`${space}/${ACTION_TYPES.CLOSE_MODAL}`)
|
|
}
|
|
}
|
|
})
|
|
const pinedHashtag = computed({
|
|
get: () => store.state.TimelineSpace.Modals.NewToot.pinedHashtag,
|
|
set: (value: boolean) => store.commit(`${space}/${MUTATION_TYPES.CHANGE_PINED_HASHTAG}`, value)
|
|
})
|
|
|
|
onMounted(() => {
|
|
store.dispatch(`${space}/${ACTION_TYPES.SETUP_LOADING}`)
|
|
EventEmitter.on('image-uploaded', () => {
|
|
if (previewRef.value) {
|
|
statusHeight.value = statusHeight.value - previewRef.value.offsetHeight
|
|
}
|
|
})
|
|
|
|
showContentWarning.value = initialSpoiler.value.length > 0
|
|
statusText.value = initialStatus.value
|
|
spoilerText.value = initialSpoiler.value
|
|
})
|
|
|
|
onBeforeUnmount(() => {
|
|
store.dispatch(`${space}/${ACTION_TYPES.TEARDOWN_LOADING}`)
|
|
})
|
|
|
|
const close = () => {
|
|
store.dispatch(`${space}/${ACTION_TYPES.RESET_MEDIA_COUNT}`)
|
|
store.dispatch(`${space}/${ACTION_TYPES.CLOSE_MODAL}`)
|
|
}
|
|
const toot = async () => {
|
|
const form = {
|
|
status: statusText.value,
|
|
spoiler: spoilerText.value,
|
|
polls: polls.value,
|
|
pollExpireSeconds: pollExpire.value
|
|
}
|
|
|
|
try {
|
|
const status = await store.dispatch(`${space}/${ACTION_TYPES.POST_TOOT}`, form)
|
|
store.dispatch(`${space}/${ACTION_TYPES.UPDATE_HASHTAGS}`, status.tags)
|
|
close()
|
|
} catch (err) {
|
|
console.error(err)
|
|
if (err instanceof NewTootTootLength) {
|
|
ElMessage({
|
|
message: i18n.t('validation.new_toot.toot_length', {
|
|
min: 1,
|
|
max: tootMax.value
|
|
}),
|
|
type: 'error'
|
|
})
|
|
} else if (err instanceof NewTootAttachLength) {
|
|
ElMessage({
|
|
message: i18n.t('validation.new_toot.attach_length', { max: 4 }),
|
|
type: 'error'
|
|
})
|
|
} else if (err instanceof NewTootPollInvalid) {
|
|
ElMessage({
|
|
message: i18n.t('validation.new_toot.poll_invalid'),
|
|
type: 'error'
|
|
})
|
|
} else if (err instanceof NewTootModalOpen || err instanceof NewTootBlockSubmit) {
|
|
// Nothing
|
|
} else {
|
|
ElMessage({
|
|
message: i18n.t('message.toot_error'),
|
|
type: 'error'
|
|
})
|
|
}
|
|
}
|
|
}
|
|
const selectImage = () => {
|
|
imageRef!.value!.click()
|
|
}
|
|
const updateImage = (file: File) => {
|
|
store
|
|
.dispatch(`${space}/${ACTION_TYPES.UPLOAD_IMAGE}`, file)
|
|
.then(() => {
|
|
enableResizing.value = false
|
|
nextTick(() => {
|
|
if (attachedMedias.value.length === 1 && previewRef.value) {
|
|
statusHeight.value = statusHeight.value - previewRef.value.offsetHeight
|
|
}
|
|
enableResizing.value = true
|
|
})
|
|
})
|
|
.catch(err => {
|
|
if (err instanceof NewTootAttachLength) {
|
|
ElMessage({
|
|
message: i18n.t('validation.new_toot.attach_length', { max: 4 }),
|
|
type: 'error'
|
|
})
|
|
} else {
|
|
ElMessage({
|
|
message: i18n.t('message.attach_error'),
|
|
type: 'error'
|
|
})
|
|
}
|
|
})
|
|
}
|
|
const onChangeImage = (e: Event) => {
|
|
const target = e.target as HTMLInputElement
|
|
const file = target.files?.item(0)
|
|
if (file === null || file === undefined) {
|
|
return
|
|
}
|
|
if (!file.type.includes('image') && !file.type.includes('video')) {
|
|
ElMessage({
|
|
message: i18n.t('validation.new_toot.attach_image'),
|
|
type: 'error'
|
|
})
|
|
return
|
|
}
|
|
updateImage(file)
|
|
}
|
|
const onPaste = (e: Event) => {
|
|
const mimeTypes = (window as any).clipboard.availableFormats().filter(t => t.startsWith('image'))
|
|
if (mimeTypes.length === 0) {
|
|
return
|
|
}
|
|
e.preventDefault()
|
|
const image = (window as any).clipboard.readImage()
|
|
let data: any
|
|
if (/^image\/jpe?g$/.test(mimeTypes[0])) {
|
|
data = image.toJPEG(100)
|
|
} else {
|
|
data = image.toPNG()
|
|
}
|
|
const file = new File([data], 'clipboard.picture', { type: mimeTypes[0] })
|
|
updateImage(file)
|
|
}
|
|
const removeAttachment = (media: Entity.Attachment) => {
|
|
const previousHeight = previewRef!.value!.offsetHeight
|
|
store.dispatch(`${space}/${ACTION_TYPES.REMOVE_MEDIA}`, media).then(() => {
|
|
enableResizing.value = false
|
|
nextTick(() => {
|
|
if (attachedMedias.value.length === 0) {
|
|
statusHeight.value = statusHeight.value + previousHeight
|
|
}
|
|
enableResizing.value = true
|
|
})
|
|
})
|
|
}
|
|
const changeVisibility = (level: number) => {
|
|
store.commit(`${space}/${MUTATION_TYPES.CHANGE_VISIBILITY_VALUE}`, level)
|
|
}
|
|
const changeSensitive = () => {
|
|
store.commit(`${space}/${MUTATION_TYPES.CHANGE_SENSITIVE}`, !sensitive.value)
|
|
}
|
|
const closeConfirm = (done: Function) => {
|
|
if (!newTootModal.value) return
|
|
if (statusRef.value?.suggestOpened) return
|
|
if (statusText.value.length === 0) {
|
|
done()
|
|
} else {
|
|
ElMessageBox.confirm(i18n.t('modals.new_toot.close_confirm'), {
|
|
confirmButtonText: i18n.t('modals.new_toot.close_confirm_ok'),
|
|
cancelButtonText: i18n.t('modals.new_toot.close_confirm_cancel')
|
|
})
|
|
.then(_ => {
|
|
done()
|
|
})
|
|
.catch(_ => {})
|
|
}
|
|
}
|
|
const updateDescription = (id: number, value: string) => {
|
|
store.commit(`${space}/${MUTATION_TYPES.UPDATE_MEDIA_DESCRIPTION}`, { id: id, description: value })
|
|
}
|
|
const togglePollForm = () => {
|
|
const previousHeight = pollRef.value ? pollRef.value.$el.offsetHeight : 0
|
|
const toggle = () => {
|
|
openPoll.value = !openPoll.value
|
|
if (openPoll.value) {
|
|
polls.value = ['', '']
|
|
} else {
|
|
polls.value = []
|
|
}
|
|
}
|
|
enableResizing.value = false
|
|
toggle()
|
|
nextTick(() => {
|
|
if (openPoll.value) {
|
|
const currentHeight = pollRef.value ? pollRef.value.$el.offsetHeight : 0
|
|
statusHeight.value = statusHeight.value - currentHeight
|
|
} else {
|
|
statusHeight.value = statusHeight.value + previousHeight
|
|
}
|
|
enableResizing.value = true
|
|
})
|
|
}
|
|
const addPoll = () => {
|
|
enableResizing.value = false
|
|
polls.value.push('')
|
|
nextTick(() => {
|
|
enableResizing.value = true
|
|
})
|
|
}
|
|
const removePoll = (id: number) => {
|
|
enableResizing.value = false
|
|
polls.value.splice(id, 1)
|
|
nextTick(() => {
|
|
enableResizing.value = true
|
|
})
|
|
}
|
|
const toggleContentWarning = () => {
|
|
const previousHeight = spoilerRef.value ? spoilerRef.value.offsetHeight : 0
|
|
enableResizing.value = false
|
|
showContentWarning.value = !showContentWarning.value
|
|
nextTick(() => {
|
|
if (showContentWarning.value) {
|
|
if (spoilerRef.value) {
|
|
statusHeight.value = statusHeight.value - spoilerRef.value.offsetHeight
|
|
}
|
|
} else {
|
|
statusHeight.value = statusHeight.value + previousHeight
|
|
}
|
|
enableResizing.value = true
|
|
})
|
|
}
|
|
const handleResize = (event: { width: number; height: number }) => {
|
|
if (!enableResizing.value) return
|
|
const dialog = document.getElementsByClassName('new-toot-modal').item(0) as HTMLElement
|
|
if (!dialog) return
|
|
const dialogStyle = window.getComputedStyle(dialog, null)
|
|
// Ignore when the modal height already reach window height.
|
|
const marginTop = dialogStyle.marginTop
|
|
const limitHeight = document.documentElement.clientHeight - parseInt(marginTop) - 80
|
|
if (dialog.offsetHeight >= limitHeight) {
|
|
return
|
|
}
|
|
const pollHeight = pollRef.value ? pollRef.value.$el.offsetHeight : 0
|
|
const spoilerHeight = spoilerRef.value ? spoilerRef.value.offsetHeight : 0
|
|
const quoteHeight = quoteRef.value ? quoteRef.value.$el.offsetHeight : 0
|
|
const previewHeight = previewRef.value ? previewRef.value.offsetHeight : 0
|
|
const headerHeight = 54
|
|
const footerHeight = 66
|
|
statusHeight.value = event.height - footerHeight - headerHeight - previewHeight - pollHeight - spoilerHeight - quoteHeight
|
|
}
|
|
|
|
return {
|
|
visibilityList,
|
|
statusText,
|
|
spoilerText,
|
|
showContentWarning,
|
|
openPoll,
|
|
polls,
|
|
pollExpire,
|
|
statusHeight,
|
|
// DOM refs
|
|
previewRef,
|
|
imageRef,
|
|
pollRef,
|
|
spoilerRef,
|
|
quoteRef,
|
|
statusRef,
|
|
// computed
|
|
quoteToMessage,
|
|
attachedMedias,
|
|
mediaDescriptions,
|
|
blockSubmit,
|
|
sensitive,
|
|
visibilityIcon,
|
|
loading,
|
|
tootMax,
|
|
displayNameStyle,
|
|
hashtagInserting,
|
|
newTootModal,
|
|
pinedHashtag,
|
|
// methods
|
|
close,
|
|
toot,
|
|
selectImage,
|
|
onChangeImage,
|
|
onPaste,
|
|
removeAttachment,
|
|
changeVisibility,
|
|
changeSensitive,
|
|
closeConfirm,
|
|
updateDescription,
|
|
togglePollForm,
|
|
addPoll,
|
|
removePoll,
|
|
toggleContentWarning,
|
|
handleResize
|
|
}
|
|
},
|
|
methods: {}
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.new-toot :deep() {
|
|
.new-toot-modal {
|
|
background-color: var(--theme-selected-background-color);
|
|
overflow: hidden;
|
|
resize: both;
|
|
padding-bottom: 20px;
|
|
max-height: calc(100% - 15vh - 80px);
|
|
max-width: 95%;
|
|
|
|
.el-dialog__header {
|
|
background-color: #4a5664;
|
|
margin-right: 0;
|
|
|
|
.el-dialog__title {
|
|
color: #ebeef5;
|
|
}
|
|
}
|
|
|
|
.el-dialog__body {
|
|
padding: 0;
|
|
|
|
.el-input__inner {
|
|
background-color: var(--theme-background-color);
|
|
color: var(--theme-primary-color);
|
|
border: 1px solid var(--theme-border-color);
|
|
}
|
|
|
|
.spoiler {
|
|
box-sizing: border-box;
|
|
padding: 4px 0;
|
|
background-color: #4a5664;
|
|
|
|
input {
|
|
border-radius: 0;
|
|
|
|
&::placeholder {
|
|
color: #c0c4cc;
|
|
}
|
|
}
|
|
}
|
|
|
|
.preview {
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
flex-flow: row wrap;
|
|
|
|
.image-wrapper {
|
|
position: relative;
|
|
flex: 1 1 0;
|
|
min-width: 10%;
|
|
height: 150px;
|
|
margin: 4px;
|
|
|
|
.preview-image {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
border: 0;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.image-description {
|
|
position: absolute;
|
|
left: 0;
|
|
bottom: 0;
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
border: 0;
|
|
border-bottom-left-radius: 8px;
|
|
border-bottom-right-radius: 8px;
|
|
background: linear-gradient(0deg, rgba(0, 0, 0, 0.8) 0, rgba(0, 0, 0, 0.35) 80%, transparent);
|
|
font-size: var(--font-base-size);
|
|
color: #fff;
|
|
opacity: 1;
|
|
resize: none;
|
|
overflow: scroll;
|
|
|
|
&::placeholder {
|
|
color: #c0c4cc;
|
|
}
|
|
}
|
|
|
|
.remove-image {
|
|
position: absolute;
|
|
top: 2px;
|
|
left: 2px;
|
|
padding: 0;
|
|
cursor: pointer;
|
|
font-size: 1.5rem;
|
|
|
|
.fa-icon {
|
|
font-size: 0.9rem;
|
|
width: auto;
|
|
height: 1em;
|
|
max-width: 100%;
|
|
max-height: 100%;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.el-dialog__footer {
|
|
background-color: var(--theme-selected-background-color);
|
|
font-size: var(--base-font-size);
|
|
padding-bottom: 0;
|
|
|
|
.upload-image {
|
|
text-align: left;
|
|
float: left;
|
|
|
|
.image-input {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
.poll {
|
|
float: left;
|
|
margin-left: 8px;
|
|
}
|
|
|
|
.privacy {
|
|
float: left;
|
|
margin-left: 8px;
|
|
}
|
|
|
|
.sensitive {
|
|
float: left;
|
|
margin-left: 8px;
|
|
}
|
|
|
|
.content-warning {
|
|
float: left;
|
|
margin-left: 8px;
|
|
|
|
.cw-text {
|
|
font-weight: 800;
|
|
line-height: 18px;
|
|
}
|
|
}
|
|
|
|
.pined-hashtag {
|
|
float: left;
|
|
margin-left: 8px;
|
|
}
|
|
|
|
.clickable {
|
|
color: #909399;
|
|
}
|
|
|
|
.info {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
align-items: center;
|
|
|
|
.loading {
|
|
width: 18px;
|
|
margin-right: 4px;
|
|
}
|
|
|
|
.text-count {
|
|
padding-right: 10px;
|
|
color: #909399;
|
|
}
|
|
}
|
|
|
|
.toot-action {
|
|
font-size: var(--base-font-size);
|
|
margin-top: 2px;
|
|
margin-bottom: 2px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.privacy-icon {
|
|
margin-right: 4px;
|
|
}
|
|
</style>
|