Editing emojis in popover, pack creation/deletion
Also fixed some API calls since they weren't working apparently
This commit is contained in:
parent
bfdad56b0d
commit
091532d577
@ -1,20 +1,46 @@
|
|||||||
|
import { clone } from 'lodash'
|
||||||
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
||||||
import StringSetting from '../helpers/string_setting.vue'
|
import StringSetting from '../helpers/string_setting.vue'
|
||||||
import Checkbox from 'components/checkbox/checkbox.vue'
|
import Checkbox from 'components/checkbox/checkbox.vue'
|
||||||
import StillImage from 'components/still-image/still-image.vue'
|
import StillImage from 'components/still-image/still-image.vue'
|
||||||
|
import Select from 'components/select/select.vue'
|
||||||
|
import Popover from 'components/popover/popover.vue'
|
||||||
|
import ConfirmModal from 'components/confirm_modal/confirm_modal.vue'
|
||||||
|
import ModifiedIndicator from '../helpers/modified_indicator.vue'
|
||||||
|
|
||||||
const EmojiTab = {
|
const EmojiTab = {
|
||||||
components: {
|
components: {
|
||||||
TabSwitcher,
|
TabSwitcher,
|
||||||
StringSetting,
|
StringSetting,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
StillImage
|
StillImage,
|
||||||
|
Select,
|
||||||
|
Popover,
|
||||||
|
ConfirmModal,
|
||||||
|
ModifiedIndicator
|
||||||
},
|
},
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
knownPacks: { },
|
knownPacks: { },
|
||||||
editedParts: { }
|
editedParts: { },
|
||||||
|
editedMetadata: { },
|
||||||
|
packName: '',
|
||||||
|
newPackName: '',
|
||||||
|
deleteModalVisible: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
pack () {
|
||||||
|
return this.packName !== '' ? this.knownPacks[this.packName] : undefined
|
||||||
|
},
|
||||||
|
packMeta () {
|
||||||
|
if (this.editedMetadata[this.packName] === undefined) {
|
||||||
|
this.editedMetadata[this.packName] = clone(this.knownPacks[this.packName].pack)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.editedMetadata[this.packName]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -25,37 +51,90 @@ const EmojiTab = {
|
|||||||
importFromFS () {
|
importFromFS () {
|
||||||
this.$store.state.api.backendInteractor.importEmojiFromFS()
|
this.$store.state.api.backendInteractor.importEmojiFromFS()
|
||||||
},
|
},
|
||||||
emojiAddr (packName, name) {
|
emojiAddr (name) {
|
||||||
return `${this.$store.state.instance.server}/emoji/${encodeURIComponent(packName)}/${name}`
|
return `${this.$store.state.instance.server}/emoji/${encodeURIComponent(this.packName)}/${name}`
|
||||||
},
|
},
|
||||||
editEmoji (packName, shortcode) {
|
|
||||||
if (this.editedParts[packName] === undefined) { this.editedParts[packName] = {} }
|
|
||||||
|
|
||||||
this.editedParts[packName][shortcode] = {
|
createEmojiPack () {
|
||||||
shortcode, file: this.knownPacks[packName].files[shortcode]
|
this.$store.state.api.backendInteractor.createEmojiPack(
|
||||||
|
{ name: this.newPackName }
|
||||||
|
).then(resp => resp.json()).then(resp => {
|
||||||
|
if (resp === 'ok') {
|
||||||
|
return this.refreshPackList()
|
||||||
|
} else {
|
||||||
|
return Promise.reject(resp)
|
||||||
|
}
|
||||||
|
}).then(done => {
|
||||||
|
this.$refs.createPackPopover.hidePopover()
|
||||||
|
|
||||||
|
this.packName = this.newPackName
|
||||||
|
this.newPackName = ''
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteEmojiPack () {
|
||||||
|
this.$store.state.api.backendInteractor.deleteEmojiPack(
|
||||||
|
{ name: this.packName }
|
||||||
|
).then(resp => resp.json()).then(resp => {
|
||||||
|
if (resp === 'ok') {
|
||||||
|
return this.refreshPackList()
|
||||||
|
} else {
|
||||||
|
return Promise.reject(resp)
|
||||||
|
}
|
||||||
|
}).then(done => {
|
||||||
|
delete this.editedMetadata[this.packName]
|
||||||
|
delete this.editedParts[this.packName]
|
||||||
|
|
||||||
|
this.deleteModalVisible = false
|
||||||
|
this.packName = ''
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
metaEdited (prop) {
|
||||||
|
return this.pack && this.packMeta[prop] !== this.pack.pack[prop]
|
||||||
|
},
|
||||||
|
savePackMetadata () {
|
||||||
|
this.$store.state.api.backendInteractor.saveEmojiPackMetadata({ name: this.packName, newData: this.packMeta }).then(
|
||||||
|
resp => resp.json()
|
||||||
|
).then(resp => {
|
||||||
|
// Update actual pack data
|
||||||
|
this.pack.pack = resp
|
||||||
|
// Delete edited pack data, should auto-update itself
|
||||||
|
delete this.editedMetadata[this.packName]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
editEmoji (shortcode) {
|
||||||
|
if (this.editedParts[this.packName] === undefined) { this.editedParts[this.packName] = {} }
|
||||||
|
|
||||||
|
if (this.editedParts[this.packName][shortcode] === undefined) {
|
||||||
|
this.editedParts[this.packName][shortcode] = {
|
||||||
|
shortcode, file: this.knownPacks[this.packName].files[shortcode]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveEditedEmoji (packName, shortcode) {
|
saveEditedEmoji (shortcode) {
|
||||||
const edited = this.editedParts[packName][shortcode]
|
const edited = this.editedParts[this.packName][shortcode]
|
||||||
|
|
||||||
this.$store.state.api.backendInteractor.updateEmojiFile(
|
this.$store.state.api.backendInteractor.updateEmojiFile(
|
||||||
{ packName, shortcode, newShortcode: edited.shortcode, newFilename: edited.file, force: false }
|
{ packName: this.packName, shortcode, newShortcode: edited.shortcode, newFilename: edited.file, force: false }
|
||||||
).then(resp =>
|
).then(resp =>
|
||||||
resp.ok ? resp.json() : resp.text().then(respText => Promise.reject(respText))
|
resp.ok ? resp.json() : resp.text().then(respText => Promise.reject(respText))
|
||||||
).then(resp => {
|
).then(resp => {
|
||||||
this.knownPacks[packName].files = resp
|
this.knownPacks[this.packName].files = resp
|
||||||
delete this.editedParts[packName][shortcode]
|
delete this.editedParts[this.packName][shortcode]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
refreshPackList () {
|
||||||
|
return this.$store.state.api.backendInteractor.listEmojiPacks()
|
||||||
|
.then(data => data.json())
|
||||||
|
.then(packData => {
|
||||||
|
this.knownPacks = packData.packs
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted () {
|
mounted () {
|
||||||
this.$store.state.api.backendInteractor.listEmojiPacks()
|
this.refreshPackList()
|
||||||
.then(data => data.json())
|
|
||||||
.then(packData => {
|
|
||||||
this.knownPacks = packData.packs
|
|
||||||
console.log(this.knownPacks)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
@import "src/variables";
|
||||||
|
|
||||||
.emoji-tab {
|
.emoji-tab {
|
||||||
.btn-group .btn {
|
.btn-group .btn {
|
||||||
margin-left: 0.5em;
|
margin-left: 0.5em;
|
||||||
@ -21,4 +23,24 @@
|
|||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.emoji-unsaved {
|
||||||
|
box-shadow: 2px 3px 5px var(--cBlue, $fallback--cBlue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1em 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-tab-edit-popover {
|
||||||
|
padding-left: 0.5em;
|
||||||
|
padding-right: 0.5em;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-tab-popover-button {
|
||||||
|
margin-left: 0.5em;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
<div class="setting-item">
|
<div class="setting-item">
|
||||||
<h2>{{ $t('admin_dash.tabs.emoji') }}</h2>
|
<h2>{{ $t('admin_dash.tabs.emoji') }}</h2>
|
||||||
|
|
||||||
<span class="btn-group">
|
<ul class="setting-list">
|
||||||
|
<li class="btn-group setting-item">
|
||||||
<button
|
<button
|
||||||
class="button button-default btn"
|
class="button button-default btn"
|
||||||
type="button"
|
type="button"
|
||||||
@ -19,71 +20,152 @@
|
|||||||
@click="importFromFS">
|
@click="importFromFS">
|
||||||
{{ $t('admin_dash.emoji.importFS') }}
|
{{ $t('admin_dash.emoji.importFS') }}
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</li>
|
||||||
|
|
||||||
<tab-switcher :scrollable-tabs="true" v-if="Object.keys(knownPacks).length > 0">
|
<li class="setting-item btn-group">
|
||||||
<div v-for="(pack, packName) in knownPacks" :label="packName" :key="packName">
|
<button
|
||||||
|
class="button button-default btn"
|
||||||
|
type="button"
|
||||||
|
@click="$refs.createPackPopover.showPopover">
|
||||||
|
Create pack
|
||||||
|
</button>
|
||||||
|
<Popover
|
||||||
|
ref="createPackPopover"
|
||||||
|
trigger="click"
|
||||||
|
placement="bottom"
|
||||||
|
bound-to-selector=".emoji-tab"
|
||||||
|
:bound-to="{ x: 'container' }"
|
||||||
|
:offset="{ y: 5 }"
|
||||||
|
>
|
||||||
|
<template #content>
|
||||||
|
<input v-model="newPackName" placeholder="New pack name">
|
||||||
|
<button
|
||||||
|
class="button button-default btn emoji-tab-popover-button"
|
||||||
|
type="button"
|
||||||
|
@click="createEmojiPack">
|
||||||
|
Create
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</Popover>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="button button-default btn"
|
||||||
|
:disabled="packName == ''"
|
||||||
|
type="button"
|
||||||
|
@click="deleteModalVisible = true">
|
||||||
|
Delete pack
|
||||||
|
</button>
|
||||||
|
<ConfirmModal
|
||||||
|
v-if="deleteModalVisible"
|
||||||
|
title="Delete?"
|
||||||
|
:cancel-text="$t('status.delete_confirm_cancel_button')"
|
||||||
|
:confirm-text="$t('status.delete_confirm_accept_button')"
|
||||||
|
@cancelled="deleteModalVisible = false"
|
||||||
|
@accepted="deleteEmojiPack" >
|
||||||
|
Are you sure you want to delete {{ packName }}?
|
||||||
|
</ConfirmModal>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<Select class="form-control" v-model="packName">
|
||||||
|
<option value="" disabled hidden>Emoji pack</option>
|
||||||
|
<option v-for="(pack, listPackName) in knownPacks" :label="listPackName" :key="listPackName">
|
||||||
|
{{ listPackName }}
|
||||||
|
</option>
|
||||||
|
</Select>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div v-if="packName !== ''">
|
||||||
<div class="pack-info-wrapper">
|
<div class="pack-info-wrapper">
|
||||||
<ul class="setting-list">
|
<ul class="setting-list">
|
||||||
<li>
|
<li>
|
||||||
<div>Description</div>
|
<div>
|
||||||
|
Description
|
||||||
|
<ModifiedIndicator :changed="metaEdited('description')" />
|
||||||
|
</div>
|
||||||
<textarea
|
<textarea
|
||||||
v-model="pack.pack.description"
|
v-model="packMeta.description"
|
||||||
class="bio resize-height" />
|
class="bio resize-height" />
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<div>Homepage</div>
|
<div>
|
||||||
<input class="emoji-info-input" v-model="pack.pack.homepage">
|
Homepage
|
||||||
|
<ModifiedIndicator :changed="metaEdited('homepage')" />
|
||||||
|
</div>
|
||||||
|
<input class="emoji-info-input" v-model="packMeta.homepage">
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<div>Fallback source</div>
|
<div>
|
||||||
<input class="emoji-info-input" v-model="pack.pack['fallback-src']">
|
Fallback source
|
||||||
|
<ModifiedIndicator :changed="metaEdited('fallback-src')" />
|
||||||
|
</div>
|
||||||
|
<input class="emoji-info-input" v-model="packMeta['fallback-src']">
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Checkbox v-model="pack.pack['can-download']">Downloadable</Checkbox>
|
<div>Fallback SHA256</div>
|
||||||
|
<input :disabled="true" class="emoji-info-input" v-model="packMeta['fallback-src-sha256']">
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Checkbox v-model="packMeta['share-files']">Share</Checkbox>
|
||||||
|
|
||||||
|
<ModifiedIndicator :changed="metaEdited('share-files')" />
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
class="button button-default btn"
|
||||||
|
type="button"
|
||||||
|
@click="savePackMetadata">
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Files</h2>
|
<h2>Files</h2>
|
||||||
|
|
||||||
<ul class="setting-list">
|
<div class="emoji-list" v-if="pack">
|
||||||
<li v-for="(file, shortcode) in pack.files" :key="shortcode">
|
<Popover
|
||||||
<StillImage
|
v-for="(file, shortcode) in pack.files" :key="shortcode"
|
||||||
class="emoji img"
|
trigger="click"
|
||||||
:src="emojiAddr(packName, file)"
|
placement="top"
|
||||||
:title="`:${shortcode}:`"
|
:class="{'emoji-unsaved': editedParts[packName] !== undefined && editedParts[packName][shortcode] !== undefined}"
|
||||||
:alt="`:${shortcode}:`"
|
popover-class="emoji-tab-edit-popover popover-default"
|
||||||
/>
|
bound-to-selector=".emoji-list"
|
||||||
|
:bound-to="{ x: 'container' }"
|
||||||
<template v-if="editedParts[packName] !== undefined && editedParts[packName][shortcode] !== undefined">
|
:offset="{ y: 5 }"
|
||||||
|
@show="editEmoji(shortcode)"
|
||||||
|
>
|
||||||
|
<template #content>
|
||||||
|
<h3>
|
||||||
|
Editing <i>{{ shortcode }}</i>
|
||||||
|
</h3>
|
||||||
|
<div v-if="editedParts[packName] !== undefined && editedParts[packName][shortcode] !== undefined">
|
||||||
<input class="emoji-data-input"
|
<input class="emoji-data-input"
|
||||||
v-model="editedParts[packName][shortcode].shortcode">
|
v-model="editedParts[packName][shortcode].shortcode">
|
||||||
<input class="emoji-data-input"
|
<input class="emoji-data-input"
|
||||||
v-model="editedParts[packName][shortcode].file">
|
v-model="editedParts[packName][shortcode].file">
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="button button-default btn"
|
class="button button-default btn emoji-tab-popover-button"
|
||||||
type="button"
|
type="button"
|
||||||
@click="saveEditedEmoji(packName, shortcode)">
|
@click="saveEditedEmoji(shortcode)">
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<input disabled class="emoji-data-input" :value="shortcode">
|
|
||||||
<input disabled class="emoji-data-input" :value="file">
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="button button-default btn"
|
|
||||||
type="button"
|
|
||||||
@click="editEmoji(packName, shortcode)">
|
|
||||||
Edit
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</tab-switcher>
|
</template>
|
||||||
|
<template #trigger>
|
||||||
|
<StillImage
|
||||||
|
class="emoji"
|
||||||
|
:src="emojiAddr(file)"
|
||||||
|
:title="`:${shortcode}:`"
|
||||||
|
:alt="`:${shortcode}:`"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
:label="$t('admin_dash.tabs.emoji')"
|
:label="$t('admin_dash.tabs.emoji')"
|
||||||
icon="laptop-code"
|
icon="face-smile-beam"
|
||||||
data-tab-name="emoji"
|
data-tab-name="emoji"
|
||||||
>
|
>
|
||||||
<EmojiTab />
|
<EmojiTab />
|
||||||
|
@ -116,12 +116,12 @@ const PLEROMA_ADMIN_FRONTENDS_INSTALL_URL = '/api/pleroma/admin/frontends/instal
|
|||||||
|
|
||||||
const PLEROMA_EMOJI_RELOAD_URL = '/api/pleroma/admin/reload_emoji'
|
const PLEROMA_EMOJI_RELOAD_URL = '/api/pleroma/admin/reload_emoji'
|
||||||
const PLEROMA_EMOJI_IMPORT_FS_URL = '/api/pleroma/emoji/packs/import'
|
const PLEROMA_EMOJI_IMPORT_FS_URL = '/api/pleroma/emoji/packs/import'
|
||||||
const PLEROMA_EMOJI_PACKS_URL = (page, pageSize) => `/api/pleroma/emoji/packs?page=${page}&page_size=${pageSize}`
|
const PLEROMA_EMOJI_PACKS_URL = (page, pageSize) => `/api/v1/pleroma/emoji/packs?page=${page}&page_size=${pageSize}`
|
||||||
const PLEROMA_EMOJI_PACK_URL = (name) => `/api/pleroma/emoji/pack?name=${name}`
|
const PLEROMA_EMOJI_PACK_URL = (name) => `/api/v1/pleroma/emoji/pack?name=${name}`
|
||||||
const PLEROMA_EMOJI_PACKS_DL_REMOTE_URL = '/api/pleroma/emoji/packs/download'
|
const PLEROMA_EMOJI_PACKS_DL_REMOTE_URL = '/api/v1/pleroma/emoji/packs/download'
|
||||||
const PLEROMA_EMOJI_PACKS_LS_REMOTE_URL =
|
const PLEROMA_EMOJI_PACKS_LS_REMOTE_URL =
|
||||||
(url, page, pageSize) => `/api/pleroma/emoji/packs/remote?url=${url}&page=${page}&page_size=${pageSize}`
|
(url, page, pageSize) => `/api/v1/pleroma/emoji/packs/remote?url=${url}&page=${page}&page_size=${pageSize}`
|
||||||
const PLEROMA_EMOJI_UPDATE_FILE_URL = (name) => `/api/pleroma/emoji/packs/files?name=${name}`
|
const PLEROMA_EMOJI_UPDATE_FILE_URL = (name) => `/api/v1/pleroma/emoji/packs/files?name=${name}`
|
||||||
|
|
||||||
const oldfetch = window.fetch
|
const oldfetch = window.fetch
|
||||||
|
|
||||||
@ -1809,7 +1809,7 @@ const importEmojiFromFS = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const createEmojiPack = ({ name }) => {
|
const createEmojiPack = ({ name }) => {
|
||||||
return fetch(PLEROMA_EMOJI_PACK_URL(name), { method: 'PUT' })
|
return fetch(PLEROMA_EMOJI_PACK_URL(name), { method: 'POST' })
|
||||||
}
|
}
|
||||||
|
|
||||||
const listEmojiPacks = () => {
|
const listEmojiPacks = () => {
|
||||||
@ -1850,7 +1850,7 @@ const saveEmojiPackMetadata = ({ name, newData }) => {
|
|||||||
{
|
{
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ name, new_data: newData })
|
body: JSON.stringify({ metadata: newData })
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user