Merge pull request #963 from h3poteto/iss-874

refs #874 Add polls form in new toot modal
This commit is contained in:
AkiraFukushima 2019-07-18 09:46:51 +09:00 committed by GitHub
commit d6e4fc1c18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 344 additions and 56 deletions

View File

@ -186,12 +186,14 @@
"close_confirm": "Möchtest du wirklich schließen?", "close_confirm": "Möchtest du wirklich schließen?",
"close_confirm_ok": "Schließen", "close_confirm_ok": "Schließen",
"close_confirm_cancel": "Abbrechen", "close_confirm_cancel": "Abbrechen",
"add_image": "Bild hinzufügen", "description": "Für Menschen mit Sehbehinderung beschreiben",
"change_visibility": "Sichtbarkeit ändern", "footer": {
"add_cw": "Inhalt hinzufügen Warnung", "add_image": "Bild hinzufügen",
"change_sensitive": "Ändern Sie empfindlich", "change_visibility": "Sichtbarkeit ändern",
"pined_hashtag": "Pin the hashtag", "change_sensitive": "Ändern Sie empfindlich",
"description": "Für Menschen mit Sehbehinderung beschreiben" "add_cw": "Inhalt hinzufügen Warnung",
"pined_hashtag": "Pin the hashtag"
}
}, },
"jump": { "jump": {
"jump_to": "Springe zu..." "jump_to": "Springe zu..."

View File

@ -27,6 +27,23 @@
"tag": "Hashtag" "tag": "Hashtag"
}, },
"modals": { "modals": {
"new_toot": {
"footer": {
"poll": "Add a poll"
},
"poll": {
"add_choice": "Add a choice",
"expires": {
"5_minutes": "5 minutes",
"30_minutes": "30 minutes",
"1_hour": "1 hour",
"6_hours": "6 hours",
"1_day": "1 day",
"3_days": "3 days",
"7_days": "7 days"
}
}
},
"shortcut": { "shortcut": {
"h": "Switch the focus to left column", "h": "Switch the focus to left column",
"l": "Switch the focus to right column", "l": "Switch the focus to right column",

View File

@ -213,12 +213,27 @@
"close_confirm": "Are you sure you want to cancel the new toot?", "close_confirm": "Are you sure you want to cancel the new toot?",
"close_confirm_ok": "OK", "close_confirm_ok": "OK",
"close_confirm_cancel": "Cancel", "close_confirm_cancel": "Cancel",
"add_image": "Add images", "description": "Describe for the visually impaired",
"change_visibility": "Change visibility", "footer": {
"add_cw": "Add content warning", "add_image": "Add images",
"change_sensitive": "Change sensitive", "poll": "Add a poll",
"pined_hashtag": "Pin the hashtag", "change_visibility": "Change visibility",
"description": "Describe for the visually impaired" "change_sensitive": "Change sensitive",
"add_cw": "Add content warning",
"pined_hashtag": "Pin the hashtag"
},
"poll": {
"add_choice": "Add a choice",
"expires": {
"5_minutes": "5 minutes",
"30_minutes": "30 minutes",
"1_hour": "1 hour",
"6_hours": "6 hours",
"1_day": "1 day",
"3_days": "3 days",
"7_days": "7 days"
}
}
}, },
"jump": { "jump": {
"jump_to": "Jump to..." "jump_to": "Jump to..."

View File

@ -207,12 +207,14 @@
"close_confirm": "Êtes-vous certain de vouloir fermer ce nouveau pouet ?", "close_confirm": "Êtes-vous certain de vouloir fermer ce nouveau pouet ?",
"close_confirm_ok": "Oui", "close_confirm_ok": "Oui",
"close_confirm_cancel": "Annuler", "close_confirm_cancel": "Annuler",
"add_image": "Ajouter une image", "description": "Décrire pour les malvoyant·e·s",
"change_visibility": "Changer la visibilité", "footer": {
"add_cw": "Ajouter un avertissement de contenu", "add_image": "Ajouter une image",
"change_sensitive": "Changer sensible", "change_visibility": "Changer la visibilité",
"pined_hashtag": "Accrochez le hashtag", "change_sensitive": "Changer sensible",
"description": "Décrire pour les malvoyant·e·s" "add_cw": "Ajouter un avertissement de contenu",
"pined_hashtag": "Accrochez le hashtag"
}
}, },
"jump": { "jump": {
"jump_to": "Aller à..." "jump_to": "Aller à..."

View File

@ -16,6 +16,25 @@
"accept": "Accept", "accept": "Accept",
"reject": "Reject" "reject": "Reject"
}, },
"modals": {
"new_toot": {
"footer": {
"poll": "Add a poll"
},
"poll": {
"add_choice": "Add a choice",
"expires": {
"5_minutes": "5 minutes",
"30_minutes": "30 minutes",
"1_hour": "1 hour",
"6_hours": "6 hours",
"1_day": "1 day",
"3_days": "3 days",
"7_days": "7 days"
}
}
}
},
"cards": { "cards": {
"toot": { "toot": {
"poll": { "poll": {

View File

@ -210,12 +210,14 @@
"close_confirm": "Sei sicuro/a di voler cancellare il nuovo toot?", "close_confirm": "Sei sicuro/a di voler cancellare il nuovo toot?",
"close_confirm_ok": "OK", "close_confirm_ok": "OK",
"close_confirm_cancel": "Annulla", "close_confirm_cancel": "Annulla",
"add_image": "Aggiungi immagini", "description": "Descrivi per i non vedenti",
"change_visibility": "Modifica visibilità", "footer": {
"add_cw": "Aggiungi avviso sui contenuti", "add_image": "Aggiungi immagini",
"change_sensitive": "Modifica sensibilità", "change_visibility": "Modifica visibilità",
"pined_hashtag": "Fissa l'hashtag", "change_sensitive": "Modifica sensibilità",
"description": "Descrivi per i non vedenti" "add_cw": "Aggiungi avviso sui contenuti",
"pined_hashtag": "Fissa l'hashtag"
}
}, },
"jump": { "jump": {
"jump_to": "Salta a..." "jump_to": "Salta a..."

View File

@ -14,6 +14,25 @@
"accept": "Accept", "accept": "Accept",
"reject": "Reject" "reject": "Reject"
}, },
"modals": {
"new_toot": {
"footer": {
"poll": "Add a poll"
},
"poll": {
"add_choice": "Add a choice",
"expires": {
"5_minutes": "5 minutes",
"30_minutes": "30 minutes",
"1_hour": "1 hour",
"6_hours": "6 hours",
"1_day": "1 day",
"3_days": "3 days",
"7_days": "7 days"
}
}
}
},
"cards": { "cards": {
"toot": { "toot": {
"poll": { "poll": {

View File

@ -212,12 +212,27 @@
"close_confirm": "本当に閉じますか?", "close_confirm": "本当に閉じますか?",
"close_confirm_ok": "閉じる", "close_confirm_ok": "閉じる",
"close_confirm_cancel": "キャンセル", "close_confirm_cancel": "キャンセル",
"add_image": "画像を添付", "description": "メディアの説明を追加",
"change_visibility": "プライバシー設定", "footer": {
"add_cw": "閲覧注意を追加", "add_image": "画像を添付",
"change_sensitive": "メディアの閲覧注意設定", "poll": "アンケートを追加",
"pined_hashtag": "ハッシュタグを固定する", "change_visibility": "プライバシー設定",
"description": "メディアの説明を追加" "change_sensitive": "メディアの閲覧注意設定",
"add_cw": "閲覧注意を追加",
"pined_hashtag": "ハッシュタグを固定する"
},
"poll": {
"add_choice": "選択肢を追加",
"expires": {
"5_minutes": "5分後",
"30_minutes": "30分後",
"1_hour": "1時間後",
"6_hours": "6時間後",
"1_day": "1日後",
"3_days": "3日後",
"7_days": "7日後"
}
}
}, },
"jump": { "jump": {
"jump_to": "移動..." "jump_to": "移動..."

View File

@ -200,13 +200,14 @@
"close_confirm": "툿 작성을 그만둘까요?", "close_confirm": "툿 작성을 그만둘까요?",
"close_confirm_ok": "예", "close_confirm_ok": "예",
"close_confirm_cancel": "취소", "close_confirm_cancel": "취소",
"add_image": "이미지 추가",
"change_visibility": "공개 범위 변경",
"add_cw": "경고 문구 추가",
"change_sensitive": "민감한 미디어 설정",
"pined_hashtag": "해시태그고정",
"description": "시각장애인을 위한 설명", "description": "시각장애인을 위한 설명",
"pinned": "고정 된 툿" "footer": {
"add_image": "이미지 추가",
"change_visibility": "공개 범위 변경",
"change_sensitive": "민감한 미디어 설정",
"add_cw": "경고 문구 추가",
"pined_hashtag": "해시태그고정"
}
}, },
"jump": { "jump": {
"jump_to": "이동" "jump_to": "이동"
@ -261,7 +262,8 @@
"reply": "답장하기", "reply": "답장하기",
"reblog": "부스트", "reblog": "부스트",
"fav": "즐겨찾기", "fav": "즐겨찾기",
"detail": "툿 자세히 보기" "detail": "툿 자세히 보기",
"pinned": "고정 된 툿"
} }
}, },
"side_bar": { "side_bar": {

View File

@ -25,6 +25,25 @@
"accept": "Accept", "accept": "Accept",
"reject": "Reject" "reject": "Reject"
}, },
"modals": {
"new_toot": {
"footer": {
"poll": "Add a poll"
},
"poll": {
"add_choice": "Add a choice",
"expires": {
"5_minutes": "5 minutes",
"30_minutes": "30 minutes",
"1_hour": "1 hour",
"6_hours": "6 hours",
"1_day": "1 day",
"3_days": "3 days",
"7_days": "7 days"
}
}
}
},
"cards": { "cards": {
"toot": { "toot": {
"poll": { "poll": {

View File

@ -186,13 +186,14 @@
"close_confirm": "Czy na pewno chcesz porzucić tworzenie wpisu?", "close_confirm": "Czy na pewno chcesz porzucić tworzenie wpisu?",
"close_confirm_ok": "OK", "close_confirm_ok": "OK",
"close_confirm_cancel": "Anuluj", "close_confirm_cancel": "Anuluj",
"add_image": "Dodaj obraz",
"change_visibility": "Zmień widoczność",
"add_cw": "Dodaj ostrzeżenie zawartości",
"change_sensitive": "Zmień wrażliwy",
"pined_hashtag": "Pin the hashtag",
"description": "Wprowadź opis dla niewidomych i niedowidzących", "description": "Wprowadź opis dla niewidomych i niedowidzących",
"pinned": "Przypięty wpis" "fotter": {
"add_image": "Dodaj obraz",
"change_visibility": "Zmień widoczność",
"change_sensitive": "Zmień wrażliwy",
"add_cw": "Dodaj ostrzeżenie zawartości",
"pined_hashtag": "Pin the hashtag"
}
}, },
"jump": { "jump": {
"jump_to": "Przejdź do…" "jump_to": "Przejdź do…"
@ -244,7 +245,8 @@
"reply": "Odpowiadać", "reply": "Odpowiadać",
"reblog": "Podbić wpisu", "reblog": "Podbić wpisu",
"fav": "Ulubiony", "fav": "Ulubiony",
"detail": "Szczegół" "detail": "Szczegół",
"pinned": "Przypięty wpis"
} }
}, },
"side_bar": { "side_bar": {

View File

@ -27,6 +27,23 @@
"tag": "Hashtag" "tag": "Hashtag"
}, },
"modals": { "modals": {
"new_toot": {
"footer": {
"poll": "Add a poll"
},
"poll": {
"add_choice": "Add a choice",
"expires": {
"5_minutes": "5 minutes",
"30_minutes": "30 minutes",
"1_hour": "1 hour",
"6_hours": "6 hours",
"1_day": "1 day",
"3_days": "3 days",
"7_days": "7 days"
}
}
},
"shortcut": { "shortcut": {
"h": "Switch the focus to left column", "h": "Switch the focus to left column",
"l": "Switch the focus to right column", "l": "Switch the focus to right column",

View File

@ -14,6 +14,14 @@
</div> </div>
<Status v-model="status" :opened="newTootModal" :fixCursorPos="hashtagInserting" @paste="onPaste" @toot="toot" /> <Status v-model="status" :opened="newTootModal" :fixCursorPos="hashtagInserting" @paste="onPaste" @toot="toot" />
</el-form> </el-form>
<Poll
v-if="openPoll"
v-model="polls"
@addPoll="addPoll"
@removePoll="removePoll"
:defaultExpire="pollExpire"
@changeExpire="changeExpire"
></Poll>
<div class="preview"> <div class="preview">
<div class="image-wrapper" v-for="media in attachedMedias" v-bind:key="media.id"> <div class="image-wrapper" v-for="media in attachedMedias" v-bind:key="media.id">
<img :src="media.preview_url" class="preview-image" /> <img :src="media.preview_url" class="preview-image" />
@ -35,14 +43,19 @@
</div> </div>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<div class="upload-image"> <div class="upload-image">
<el-button size="small" type="text" @click="selectImage" :title="$t('modals.new_toot.add_image')"> <el-button size="small" type="text" @click="selectImage" :title="$t('modals.new_toot.footer.add_image')">
<icon name="camera"></icon> <icon name="camera"></icon>
</el-button> </el-button>
<input name="image" type="file" class="image-input" ref="image" @change="onChangeImage" :key="attachedMediaId" /> <input name="image" type="file" class="image-input" ref="image" @change="onChangeImage" :key="attachedMediaId" />
</div> </div>
<div class="poll">
<el-button size="small" type="text" @click="togglePollForm" :title="$t('modals.new_toot.footer.poll')">
<icon name="poll"></icon>
</el-button>
</div>
<div class="privacy"> <div class="privacy">
<el-dropdown trigger="click" @command="changeVisibility"> <el-dropdown trigger="click" @command="changeVisibility">
<el-button size="small" type="text" :title="$t('modals.new_toot.change_visibility')"> <el-button size="small" type="text" :title="$t('modals.new_toot.footer.change_visibility')">
<icon :name="visibilityIcon"></icon> <icon :name="visibilityIcon"></icon>
</el-button> </el-button>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
@ -70,7 +83,7 @@
size="small" size="small"
type="text" type="text"
@click="changeSensitive" @click="changeSensitive"
:title="$t('modals.new_toot.change_sensitive')" :title="$t('modals.new_toot.footer.change_sensitive')"
:aria-pressed="sensitive" :aria-pressed="sensitive"
> >
<icon name="eye-slash" v-show="!sensitive"></icon> <icon name="eye-slash" v-show="!sensitive"></icon>
@ -82,7 +95,7 @@
size="small" size="small"
type="text" type="text"
@click="showContentWarning = !showContentWarning" @click="showContentWarning = !showContentWarning"
:title="$t('modals.new_toot.add_cw')" :title="$t('modals.new_toot.footer.add_cw')"
:class="showContentWarning ? '' : 'clickable'" :class="showContentWarning ? '' : 'clickable'"
:aria-pressed="showContentWarning" :aria-pressed="showContentWarning"
> >
@ -94,7 +107,7 @@
size="small" size="small"
type="text" type="text"
@click="pinedHashtag = !pinedHashtag" @click="pinedHashtag = !pinedHashtag"
:title="$t('modals.new_toot.pined_hashtag')" :title="$t('modals.new_toot.footer.pined_hashtag')"
:class="pinedHashtag ? '' : 'clickable'" :class="pinedHashtag ? '' : 'clickable'"
:aria-pressed="pinedHashtag" :aria-pressed="pinedHashtag"
> >
@ -120,19 +133,27 @@ import { mapState, mapGetters } from 'vuex'
import { clipboard } from 'electron' import { clipboard } from 'electron'
import Visibility from '~/src/constants/visibility' import Visibility from '~/src/constants/visibility'
import Status from './NewToot/Status' import Status from './NewToot/Status'
import Poll from './NewToot/Poll'
import { NewTootTootLength, NewTootAttachLength, NewTootModalOpen, NewTootBlockSubmit } from '@/errors/validations' import { NewTootTootLength, NewTootAttachLength, NewTootModalOpen, NewTootBlockSubmit } from '@/errors/validations'
export default { export default {
name: 'new-toot', name: 'new-toot',
components: { components: {
Status Status,
Poll
}, },
data() { data() {
return { return {
status: '', status: '',
spoiler: '', spoiler: '',
showContentWarning: false, showContentWarning: false,
visibilityList: Visibility visibilityList: Visibility,
openPoll: false,
polls: ['', ''],
pollExpire: {
label: this.$t('modals.new_toot.poll.expires.1_day'),
value: 3600 * 24
}
} }
}, },
computed: { computed: {
@ -208,13 +229,20 @@ export default {
methods: { methods: {
close() { close() {
this.filteredAccount = [] this.filteredAccount = []
this.polls = ['', '']
this.pollExpire = {
label: this.$t('modals.new_toot.poll.expires.1_day'),
value: 3600 * 24
}
this.$store.dispatch('TimelineSpace/Modals/NewToot/resetMediaCount') this.$store.dispatch('TimelineSpace/Modals/NewToot/resetMediaCount')
this.$store.dispatch('TimelineSpace/Modals/NewToot/closeModal') this.$store.dispatch('TimelineSpace/Modals/NewToot/closeModal')
}, },
async toot() { async toot() {
const form = { const form = {
status: this.status, status: this.status,
spoiler: this.spoiler spoiler: this.spoiler,
polls: this.polls,
pollExpireSeconds: this.pollExpire.value
} }
try { try {
@ -323,6 +351,18 @@ export default {
}, },
updateDescription(id, value) { updateDescription(id, value) {
this.$store.commit('TimelineSpace/Modals/NewToot/updateMediaDescription', { id: id, description: value }) this.$store.commit('TimelineSpace/Modals/NewToot/updateMediaDescription', { id: id, description: value })
},
togglePollForm() {
this.openPoll = !this.openPoll
},
addPoll() {
this.polls.push('')
},
removePoll(id) {
this.polls.splice(id, 1)
},
changeExpire(obj) {
this.pollExpire = obj
} }
} }
} }
@ -429,6 +469,11 @@ export default {
} }
} }
.poll {
float: left;
margin-left: 8px;
}
.privacy { .privacy {
float: left; float: left;
margin-left: 8px; margin-left: 8px;

View File

@ -0,0 +1,99 @@
<template>
<div class="poll">
<ul class="poll-list">
<li class="poll-option" v-for="(option, id) in value" v-bind:key="id">
<el-radio :disabled="true" :label="id">
<el-input :placeholder="`choice ${id}`" :value="value[id]" @input="value => updateOption(value, id)" size="small"></el-input>
<el-button class="remove-poll" type="text" @click="removePoll(id)" size="small"><icon name="times"></icon></el-button>
</el-radio>
</li>
</ul>
<el-button class="add-poll" type="info" size="small" @click="addPoll" plain>{{ $t('modals.new_toot.poll.add_choice') }}</el-button>
<el-select v-model="expiresIn" size="small" value-key="value" @change="changeExpire">
<el-option v-for="exp in expires" :key="exp.value" :label="exp.label" :value="exp"> </el-option>
</el-select>
</div>
</template>
<script>
export default {
name: 'poll',
props: ['value', 'defaultExpire'],
data() {
return {
expires: [
{
label: this.$t('modals.new_toot.poll.expires.5_minutes'),
value: 60 * 5
},
{
label: this.$t('modals.new_toot.poll.expires.30_minutes'),
value: 60 * 30
},
{
label: this.$t('modals.new_toot.poll.expires.1_hour'),
value: 3600
},
{
label: this.$t('modals.new_toot.poll.expires.6_hours'),
value: 3600 * 6
},
{
label: this.$t('modals.new_toot.poll.expires.1_day'),
value: 3600 * 24
},
{
label: this.$t('modals.new_toot.poll.expires.3_days'),
value: 3600 * 24 * 3
},
{
label: this.$t('modals.new_toot.poll.expires.7_days'),
value: 3600 * 24 * 7
}
],
expiresIn: null
}
},
created() {
this.expiresIn = this.defaultExpire
},
methods: {
addPoll() {
this.$emit('addPoll')
},
removePoll(id) {
this.$emit('removePoll', id)
},
updateOption(item, index) {
const newValue = [...this.value.slice(0, index), item, ...this.value.slice(index + 1)]
this.$emit('input', newValue)
},
changeExpire(exp) {
this.$emit('changeExpire', exp)
}
}
}
</script>
<style lang="scss" scoped>
.poll {
border-top: 1px solid #ebebeb;
.poll-list {
list-style: none;
padding-left: 16px;
.poll-option {
line-height: 38px;
.remove-poll {
margin-left: 4px;
}
}
}
.add-poll {
margin: 0 0 8px 40px;
}
}
</style>

View File

@ -20,6 +20,13 @@ type MediaDescription = {
description: string description: string
} }
type TootForm = {
status: string
spoiler: string
polls: Array<string>
pollExpireSeconds: number
}
export type NewTootState = { export type NewTootState = {
modalOpen: boolean modalOpen: boolean
initialStatus: string initialStatus: string
@ -177,12 +184,12 @@ const actions: ActionTree<NewTootState, RootState> = {
throw err throw err
}) })
}, },
postToot: async ({ state, commit, rootState, dispatch }, { status, spoiler }): Promise<Status> => { postToot: async ({ state, commit, rootState, dispatch }, params: TootForm): Promise<Status> => {
if (!state.modalOpen) { if (!state.modalOpen) {
throw new NewTootModalOpen() throw new NewTootModalOpen()
} }
if (status.length < 1 || status.length > rootState.TimelineSpace.tootMax) { if (params.status.length < 1 || params.status.length > rootState.TimelineSpace.tootMax) {
throw new NewTootTootLength() throw new NewTootTootLength()
} }
@ -193,11 +200,17 @@ const actions: ActionTree<NewTootState, RootState> = {
if (visibilityKey !== undefined) { if (visibilityKey !== undefined) {
specifiedVisibility = Visibility[visibilityKey].key specifiedVisibility = Visibility[visibilityKey].key
} }
let form = { let form = {
status: status, status: params.status,
visibility: specifiedVisibility, visibility: specifiedVisibility,
sensitive: state.sensitive, sensitive: state.sensitive,
spoiler_text: spoiler spoiler_text: params.spoiler,
poll: {
expires_in: params.pollExpireSeconds,
multiple: false,
options: params.polls
}
} }
if (state.replyToMessage !== null) { if (state.replyToMessage !== null) {