Merge remote-tracking branch 'origin/admin-emoji-settings' into shigusegubu-vue3
This commit is contained in:
commit
088f2de294
7 changed files with 631 additions and 107 deletions
1
changelog.d/admin-emoji-packs.add
Normal file
1
changelog.d/admin-emoji-packs.add
Normal file
|
@ -0,0 +1 @@
|
|||
Added emoji pack management to the admin panel
|
|
@ -1,20 +1,63 @@
|
|||
import { clone, assign } from 'lodash'
|
||||
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
||||
import StringSetting from '../helpers/string_setting.vue'
|
||||
import Checkbox from 'components/checkbox/checkbox.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 newEmojiUploadBase = { shortcode: '', file: '', upload: [] }
|
||||
|
||||
const EmojiTab = {
|
||||
components: {
|
||||
TabSwitcher,
|
||||
StringSetting,
|
||||
Checkbox,
|
||||
StillImage
|
||||
StillImage,
|
||||
Select,
|
||||
Popover,
|
||||
ConfirmModal,
|
||||
ModifiedIndicator
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
knownPacks: { },
|
||||
editedParts: { }
|
||||
knownLocalPacks: { },
|
||||
knownRemotePacks: { },
|
||||
editedParts: { },
|
||||
editedMetadata: { },
|
||||
packName: '',
|
||||
newPackName: '',
|
||||
deleteModalVisible: false,
|
||||
newEmojiUpload: clone(newEmojiUploadBase),
|
||||
remotePackInstance: '',
|
||||
remotePackDownloadAs: ''
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
pack () {
|
||||
return this.packName !== '' ? this.knownPacks[this.packName] : undefined
|
||||
},
|
||||
packMeta () {
|
||||
if (this.editedMetadata[this.packName] === undefined) {
|
||||
this.editedMetadata[this.packName] = clone(this.pack.pack)
|
||||
}
|
||||
|
||||
return this.editedMetadata[this.packName]
|
||||
},
|
||||
knownPacks () {
|
||||
// Copy the object itself but not the children, so they are still passed by reference and modified
|
||||
const result = clone(this.knownLocalPacks)
|
||||
for (const instName in this.knownRemotePacks) {
|
||||
for (const instPack in this.knownRemotePacks[instName]) {
|
||||
result[`${instPack}@${instName}`] = this.knownRemotePacks[instName][instPack]
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -25,37 +68,247 @@ const EmojiTab = {
|
|||
importFromFS () {
|
||||
this.$store.state.api.backendInteractor.importEmojiFromFS()
|
||||
},
|
||||
emojiAddr (packName, name) {
|
||||
return `${this.$store.state.instance.server}/emoji/${encodeURIComponent(packName)}/${name}`
|
||||
},
|
||||
editEmoji (packName, shortcode) {
|
||||
if (this.editedParts[packName] === undefined) { this.editedParts[packName] = {} }
|
||||
|
||||
this.editedParts[packName][shortcode] = {
|
||||
shortcode, file: this.knownPacks[packName].files[shortcode]
|
||||
emojiAddr (name) {
|
||||
if (this.pack.remote !== undefined) {
|
||||
// Remote pack
|
||||
return `${this.pack.remote.instance}/emoji/${encodeURIComponent(this.pack.remote.baseName)}/${name}`
|
||||
} else {
|
||||
return `${this.$store.state.instance.server}/emoji/${encodeURIComponent(this.packName)}/${name}`
|
||||
}
|
||||
},
|
||||
saveEditedEmoji (packName, shortcode) {
|
||||
const edited = this.editedParts[packName][shortcode]
|
||||
|
||||
uploadEmoji () {
|
||||
this.$refs.addEmojiPopover.hidePopover()
|
||||
|
||||
this.$store.state.api.backendInteractor.addNewEmojiFile({
|
||||
packName: this.packName,
|
||||
file: this.newEmojiUpload.upload[0],
|
||||
shortcode: this.newEmojiUpload.shortcode,
|
||||
filename: this.newEmojiUpload.file
|
||||
}).then(resp => resp.json()).then(resp => {
|
||||
if (resp.error !== undefined) {
|
||||
this.displayError(resp.error)
|
||||
return
|
||||
}
|
||||
|
||||
this.pack.files = resp
|
||||
this.sortPackFiles(this.packName)
|
||||
|
||||
this.newEmojiUpload = clone(newEmojiUploadBase)
|
||||
})
|
||||
},
|
||||
|
||||
createEmojiPack () {
|
||||
this.$store.state.api.backendInteractor.createEmojiPack(
|
||||
{ name: this.newPackName }
|
||||
).then(resp => resp.json()).then(resp => {
|
||||
if (resp === 'ok') {
|
||||
return this.refreshPackList()
|
||||
} else {
|
||||
this.displayError(resp.error)
|
||||
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 {
|
||||
this.displayError(resp.error)
|
||||
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 => {
|
||||
if (resp.error !== undefined) {
|
||||
this.displayError(resp.error)
|
||||
return
|
||||
}
|
||||
|
||||
// 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.pack.files[shortcode]
|
||||
}
|
||||
}
|
||||
},
|
||||
deleteEmoji (shortcode) {
|
||||
this.editedParts[this.packName][shortcode].deleteModalVisible = false
|
||||
|
||||
this.$store.state.api.backendInteractor.deleteEmojiFile(
|
||||
{ packName: this.packName, shortcode }
|
||||
).then(resp => resp.json()).then(resp => {
|
||||
if (resp.error !== undefined) {
|
||||
this.displayError(resp.error)
|
||||
return
|
||||
}
|
||||
|
||||
this.pack.files = resp
|
||||
delete this.editedParts[this.packName][shortcode]
|
||||
|
||||
this.sortPackFiles(this.packName)
|
||||
})
|
||||
},
|
||||
saveEditedEmoji (shortcode) {
|
||||
const edited = this.editedParts[this.packName][shortcode]
|
||||
|
||||
if (edited.shortcode === shortcode && edited.file === this.pack.files[shortcode]) {
|
||||
delete this.editedParts[this.packName][shortcode]
|
||||
return
|
||||
}
|
||||
|
||||
this.$store.state.api.backendInteractor.updateEmojiFile(
|
||||
{ packName, shortcode, newShortcode: edited.shortcode, newFilename: edited.file, force: false }
|
||||
).then(resp =>
|
||||
resp.ok ? resp.json() : resp.text().then(respText => Promise.reject(respText))
|
||||
{ packName: this.packName, shortcode, newShortcode: edited.shortcode, newFilename: edited.file, force: false }
|
||||
).then(resp => {
|
||||
this.knownPacks[packName].files = resp
|
||||
delete this.editedParts[packName][shortcode]
|
||||
if (resp.error !== undefined) {
|
||||
this.displayError(resp.error)
|
||||
return Promise.reject(resp.error)
|
||||
}
|
||||
|
||||
return resp.json()
|
||||
}).then(resp => {
|
||||
this.pack.files = resp
|
||||
delete this.editedParts[this.packName][shortcode]
|
||||
|
||||
this.sortPackFiles(this.packName)
|
||||
})
|
||||
},
|
||||
|
||||
loadPacksPaginated (listFunction) {
|
||||
const pageSize = 25
|
||||
const allPacks = {}
|
||||
|
||||
return listFunction({ instance: this.remotePackInstance, page: 1, pageSize: 0 })
|
||||
.then(data => data.json())
|
||||
.then(data => {
|
||||
if (data.error !== undefined) { return Promise.reject(data.error) }
|
||||
|
||||
let resultingPromise = Promise.resolve({})
|
||||
for (let i = 0; i < Math.ceil(data.count / pageSize); i++) {
|
||||
resultingPromise = resultingPromise.then(() => listFunction({ instance: this.remotePackInstance, page: i, pageSize })
|
||||
).then(data => data.json()).then(pageData => {
|
||||
if (pageData.error !== undefined) { return Promise.reject(pageData.error) }
|
||||
|
||||
assign(allPacks, pageData.packs)
|
||||
})
|
||||
}
|
||||
|
||||
return resultingPromise
|
||||
})
|
||||
.then(finished => allPacks)
|
||||
.catch(data => {
|
||||
this.displayError(data)
|
||||
})
|
||||
},
|
||||
|
||||
refreshPackList () {
|
||||
this.loadPacksPaginated(this.$store.state.api.backendInteractor.listEmojiPacks)
|
||||
.then(allPacks => {
|
||||
this.knownLocalPacks = allPacks
|
||||
for (const name of Object.keys(this.knownLocalPacks)) {
|
||||
this.sortPackFiles(name)
|
||||
}
|
||||
})
|
||||
},
|
||||
listRemotePacks () {
|
||||
this.loadPacksPaginated(this.$store.state.api.backendInteractor.listRemoteEmojiPacks)
|
||||
.then(allPacks => {
|
||||
let inst = this.remotePackInstance
|
||||
if (!inst.startsWith('http')) { inst = 'https://' + inst }
|
||||
const instUrl = new URL(inst)
|
||||
inst = instUrl.host
|
||||
|
||||
for (const packName in allPacks) {
|
||||
allPacks[packName].remote = {
|
||||
baseName: packName,
|
||||
instance: instUrl.origin
|
||||
}
|
||||
}
|
||||
|
||||
this.knownRemotePacks[inst] = allPacks
|
||||
for (const pack in this.knownRemotePacks[inst]) {
|
||||
this.sortPackFiles(`${pack}@${inst}`)
|
||||
}
|
||||
|
||||
this.$refs.remotePackPopover.hidePopover()
|
||||
})
|
||||
.catch(data => {
|
||||
this.displayError(data)
|
||||
})
|
||||
},
|
||||
downloadRemotePack () {
|
||||
if (this.remotePackDownloadAs.trim() === '') {
|
||||
this.remotePackDownloadAs = this.pack.remote.baseName
|
||||
}
|
||||
|
||||
this.$store.state.api.backendInteractor.downloadRemoteEmojiPack({
|
||||
instance: this.pack.remote.instance, packName: this.pack.remote.baseName, as: this.remotePackDownloadAs
|
||||
})
|
||||
.then(data => data.json())
|
||||
.then(resp => {
|
||||
if (resp === 'ok') {
|
||||
this.$refs.dlPackPopover.hidePopover()
|
||||
|
||||
return this.refreshPackList()
|
||||
} else {
|
||||
this.displayError(resp.error)
|
||||
return Promise.reject(resp)
|
||||
}
|
||||
}).then(done => {
|
||||
this.packName = this.remotePackDownloadAs
|
||||
this.remotePackDownloadAs = ''
|
||||
})
|
||||
},
|
||||
displayError (msg) {
|
||||
this.$store.dispatch('pushGlobalNotice', {
|
||||
messageKey: 'admin_dash.emoji.error',
|
||||
messageArgs: [msg],
|
||||
level: 'error'
|
||||
})
|
||||
},
|
||||
sortPackFiles (nameOfPack) {
|
||||
// Sort by key
|
||||
const sorted = Object.keys(this.knownPacks[nameOfPack].files).sort().reduce((acc, key) => {
|
||||
if (key.length === 0) return acc
|
||||
acc[key] = this.knownPacks[nameOfPack].files[key]
|
||||
return acc
|
||||
}, {})
|
||||
this.knownPacks[nameOfPack].files = sorted
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.$store.state.api.backendInteractor.listEmojiPacks()
|
||||
.then(data => data.json())
|
||||
.then(packData => {
|
||||
this.knownPacks = packData.packs
|
||||
console.log(this.knownPacks)
|
||||
})
|
||||
this.refreshPackList()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
@import "src/variables";
|
||||
|
||||
.emoji-tab {
|
||||
.btn-group .btn {
|
||||
margin-left: 0.5em;
|
||||
|
@ -21,4 +23,33 @@
|
|||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.emoji-unsaved {
|
||||
box-shadow: 0 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;
|
||||
}
|
||||
|
||||
.emoji-tab-popover-input {
|
||||
width: 20em;
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,84 +6,297 @@
|
|||
<div class="setting-item">
|
||||
<h2>{{ $t('admin_dash.tabs.emoji') }}</h2>
|
||||
|
||||
<span class="btn-group">
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="reloadEmoji">
|
||||
{{ $t('admin_dash.emoji.reload') }}
|
||||
</button>
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="importFromFS">
|
||||
{{ $t('admin_dash.emoji.importFS') }}
|
||||
</button>
|
||||
</span>
|
||||
<ul class="setting-list">
|
||||
<li class="btn-group setting-item">
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="reloadEmoji">
|
||||
{{ $t('admin_dash.emoji.reload') }}
|
||||
</button>
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="importFromFS">
|
||||
{{ $t('admin_dash.emoji.importFS') }}
|
||||
</button>
|
||||
</li>
|
||||
|
||||
<tab-switcher :scrollable-tabs="true" v-if="Object.keys(knownPacks).length > 0">
|
||||
<div v-for="(pack, packName) in knownPacks" :label="packName" :key="packName">
|
||||
<div class="pack-info-wrapper">
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<div>Description</div>
|
||||
<textarea
|
||||
v-model="pack.pack.description"
|
||||
class="bio resize-height" />
|
||||
</li>
|
||||
<li>
|
||||
<div>Homepage</div>
|
||||
<input class="emoji-info-input" v-model="pack.pack.homepage">
|
||||
</li>
|
||||
<li>
|
||||
<div>Fallback source</div>
|
||||
<input class="emoji-info-input" v-model="pack.pack['fallback-src']">
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="pack.pack['can-download']">Downloadable</Checkbox>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<li class="btn-group setting-item">
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="$refs.createPackPopover.showPopover">
|
||||
{{ $t('admin_dash.emoji.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="$t('admin_dash.emoji.new_pack_name')">
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="createEmojiPack">
|
||||
{{ $t('admin_dash.emoji.create') }}
|
||||
</button>
|
||||
</template>
|
||||
</Popover>
|
||||
|
||||
<h2>Files</h2>
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="$refs.remotePackPopover.showPopover">
|
||||
{{ $t('admin_dash.emoji.remote_packs') }}
|
||||
|
||||
<Popover
|
||||
ref="remotePackPopover"
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
bound-to-selector=".emoji-tab"
|
||||
:bound-to="{ x: 'container' }"
|
||||
:offset="{ y: 5 }"
|
||||
>
|
||||
<template #content>
|
||||
<input v-model="remotePackInstance" :placeholder="$t('admin_dash.emoji.remote_pack_instance')">
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="listRemotePacks">
|
||||
{{ $t('admin_dash.emoji.do_list') }}
|
||||
</button>
|
||||
</template>
|
||||
</Popover>
|
||||
</button>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<Select class="form-control" v-model="packName">
|
||||
<option value="" disabled hidden>{{ $t('admin_dash.emoji.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">
|
||||
<ul class="setting-list">
|
||||
<li v-for="(file, shortcode) in pack.files" :key="shortcode">
|
||||
<StillImage
|
||||
class="emoji img"
|
||||
:src="emojiAddr(packName, file)"
|
||||
:title="`:${shortcode}:`"
|
||||
:alt="`:${shortcode}:`"
|
||||
/>
|
||||
<li>
|
||||
<div>
|
||||
{{ $t('admin_dash.emoji.description') }}
|
||||
<ModifiedIndicator :changed="metaEdited('description')" />
|
||||
</div>
|
||||
<textarea
|
||||
v-model="packMeta.description"
|
||||
:disabled="pack.remote !== undefined"
|
||||
class="bio resize-height" />
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
{{ $t('admin_dash.emoji.homepage') }}
|
||||
<ModifiedIndicator :changed="metaEdited('homepage')" />
|
||||
</div>
|
||||
<input
|
||||
class="emoji-info-input" v-model="packMeta.homepage"
|
||||
:disabled="pack.remote !== undefined">
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
{{ $t('admin_dash.emoji.fallback_src') }}
|
||||
<ModifiedIndicator :changed="metaEdited('fallback-src')" />
|
||||
</div>
|
||||
<input class="emoji-info-input" v-model="packMeta['fallback-src']" :disabled="pack.remote !== undefined">
|
||||
</li>
|
||||
<li>
|
||||
<div>{{ $t('admin_dash.emoji.fallback_sha256') }}</div>
|
||||
<input :disabled="true" class="emoji-info-input" v-model="packMeta['fallback-src-sha256']">
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox :disabled="pack.remote !== undefined" v-model="packMeta['share-files']">
|
||||
{{ $t('admin_dash.emoji.share') }}
|
||||
</Checkbox>
|
||||
|
||||
<template v-if="editedParts[packName] !== undefined && editedParts[packName][shortcode] !== undefined">
|
||||
<ModifiedIndicator :changed="metaEdited('share-files')" />
|
||||
</li>
|
||||
<li class="btn-group">
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
v-if="pack.remote === undefined"
|
||||
@click="savePackMetadata">
|
||||
{{ $t('admin_dash.emoji.save') }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
v-if="pack.remote === undefined"
|
||||
@click="$refs.addEmojiPopover.showPopover">
|
||||
{{ $t('admin_dash.emoji.add_file') }}
|
||||
|
||||
<Popover
|
||||
ref="addEmojiPopover"
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
bound-to-selector=".emoji-tab"
|
||||
popover-class="emoji-tab-edit-popover popover-default"
|
||||
:bound-to="{ x: 'container' }"
|
||||
:offset="{ y: 5 }"
|
||||
>
|
||||
<template #content>
|
||||
<h3>{{ $t('admin_dash.emoji.adding_new') }}</h3>
|
||||
<div>
|
||||
<input
|
||||
type="file"
|
||||
class="emoji-tab-popover-input emoji-tab-popover-file"
|
||||
@change="newEmojiUpload.upload = $event.target.files"
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<input class="emoji-data-input emoji-tab-popover-input"
|
||||
v-model="newEmojiUpload.shortcode"
|
||||
:placeholder="$t('admin_dash.emoji.new_shortcode')">
|
||||
<input class="emoji-data-input emoji-tab-popover-input"
|
||||
v-model="newEmojiUpload.file"
|
||||
:placeholder="$t('admin_dash.emoji.new_filename')">
|
||||
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
:disabled="this.newEmojiUpload.upload.length == 0"
|
||||
@click="uploadEmoji">
|
||||
{{ $t('admin_dash.emoji.save') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="button button-default btn"
|
||||
v-if="pack.remote === undefined"
|
||||
type="button"
|
||||
@click="deleteModalVisible = true">
|
||||
{{ $t('admin_dash.emoji.delete_pack') }}
|
||||
|
||||
<ConfirmModal
|
||||
v-if="deleteModalVisible"
|
||||
:title="$t('admin_dash.emoji.delete_title')"
|
||||
:cancel-text="$t('status.delete_confirm_cancel_button')"
|
||||
:confirm-text="$t('status.delete_confirm_accept_button')"
|
||||
@cancelled="deleteModalVisible = false"
|
||||
@accepted="deleteEmojiPack" >
|
||||
{{ $t('admin_dash.emoji.delete_confirm', [packName]) }}
|
||||
</ConfirmModal>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
v-if="pack.remote !== undefined"
|
||||
@click="$refs.dlPackPopover.showPopover">
|
||||
{{ $t('admin_dash.emoji.download_pack') }}
|
||||
|
||||
<Popover
|
||||
ref="dlPackPopover"
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
bound-to-selector=".emoji-tab"
|
||||
popover-class="emoji-tab-edit-popover popover-default"
|
||||
:bound-to="{ x: 'container' }"
|
||||
:offset="{ y: 5 }"
|
||||
>
|
||||
<template #content>
|
||||
<h3>{{ $t('admin_dash.emoji.downloading_pack', [packName]) }}</h3>
|
||||
<div>
|
||||
<div>
|
||||
<input class="emoji-data-input emoji-tab-popover-input"
|
||||
v-model="remotePackDownloadAs"
|
||||
:placeholder="$t('admin_dash.emoji.download_as_name')">
|
||||
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="downloadRemotePack">
|
||||
{{ $t('admin_dash.emoji.download') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2>{{ $t('admin_dash.emoji.files') }}</h2>
|
||||
|
||||
<div class="emoji-list" v-if="pack">
|
||||
<Popover
|
||||
v-for="(file, shortcode) in pack.files" :key="shortcode"
|
||||
trigger="click"
|
||||
:disabled="pack.remote !== undefined"
|
||||
placement="top"
|
||||
:class="{'emoji-unsaved': editedParts[packName] !== undefined && editedParts[packName][shortcode] !== undefined}"
|
||||
popover-class="emoji-tab-edit-popover popover-default"
|
||||
bound-to-selector=".emoji-list"
|
||||
:bound-to="{ x: 'container' }"
|
||||
:offset="{ y: 5 }"
|
||||
@show="editEmoji(shortcode)"
|
||||
>
|
||||
<template #content>
|
||||
<h3>
|
||||
{{ $t('admin_dash.emoji.editing', [shortcode]) }}
|
||||
</h3>
|
||||
<div v-if="editedParts[packName] !== undefined && editedParts[packName][shortcode] !== undefined">
|
||||
<input class="emoji-data-input"
|
||||
v-model="editedParts[packName][shortcode].shortcode">
|
||||
<input class="emoji-data-input"
|
||||
v-model="editedParts[packName][shortcode].file">
|
||||
|
||||
<button
|
||||
class="button button-default btn"
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="saveEditedEmoji(packName, shortcode)">
|
||||
Save
|
||||
@click="saveEditedEmoji(shortcode)">
|
||||
{{ $t('admin_dash.emoji.save') }}
|
||||
</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"
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="editEmoji(packName, shortcode)">
|
||||
Edit
|
||||
@click="editedParts[packName][shortcode].deleteModalVisible = true">
|
||||
{{ $t('admin_dash.emoji.delete') }}
|
||||
</button>
|
||||
</template>
|
||||
</li>
|
||||
</ul>
|
||||
<ConfirmModal
|
||||
v-if="editedParts[packName][shortcode].deleteModalVisible"
|
||||
:title="$t('admin_dash.emoji.delete_title')"
|
||||
:cancel-text="$t('status.delete_confirm_cancel_button')"
|
||||
:confirm-text="$t('status.delete_confirm_accept_button')"
|
||||
@cancelled="editedParts[packName][shortcode].deleteModalVisible = false"
|
||||
@accepted="deleteEmoji(shortcode)" >
|
||||
{{ $t('admin_dash.emoji.delete_confirm', [shortcode]) }}
|
||||
</ConfirmModal>
|
||||
</div>
|
||||
</template>
|
||||
<template #trigger>
|
||||
<StillImage
|
||||
class="emoji"
|
||||
:src="emojiAddr(file)"
|
||||
:title="`:${shortcode}:`"
|
||||
:alt="`:${shortcode}:`"
|
||||
/>
|
||||
</template>
|
||||
</Popover>
|
||||
</div>
|
||||
</tab-switcher>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.emoji')"
|
||||
icon="laptop-code"
|
||||
icon="face-smile-beam"
|
||||
data-tab-name="emoji"
|
||||
>
|
||||
<EmojiTab />
|
||||
|
|
|
@ -935,7 +935,35 @@
|
|||
},
|
||||
"emoji": {
|
||||
"reload": "Reload emoji",
|
||||
"importFS": "Import emoji from filesystem"
|
||||
"importFS": "Import emoji from filesystem",
|
||||
"error": "Error: {0}",
|
||||
"create_pack": "Create pack",
|
||||
"delete_pack": "Delete pack",
|
||||
"new_pack_name": "New pack name",
|
||||
"create": "Create",
|
||||
"remote_packs": "Remote packs",
|
||||
"do_list": "List",
|
||||
"remote_pack_instance": "Remote pack instance",
|
||||
"emoji_pack": "Emoji pack",
|
||||
"description": "Description",
|
||||
"homepage": "Homepage",
|
||||
"fallback_src": "Fallback source",
|
||||
"fallback_sha256": "Fallback SHA256",
|
||||
"share": "Share",
|
||||
"save": "Save",
|
||||
"delete": "Delete",
|
||||
"add_file": "Add file",
|
||||
"adding_new": "Adding new emoji",
|
||||
"new_shortcode": "Shortcode, leave blank to infer",
|
||||
"new_filename": "Filename, leave blank to infer",
|
||||
"delete_confirm": "Are you sure you want to delete {0}?",
|
||||
"download_pack": "Download pack",
|
||||
"downloading_pack": "Downloading {0}",
|
||||
"download": "Download",
|
||||
"download_as_name": "New name, leave blank to reuse",
|
||||
"files": "Files",
|
||||
"editing": "Editing {0}",
|
||||
"delete_title": "Delete?"
|
||||
},
|
||||
"temp_overrides": {
|
||||
":pleroma": {
|
||||
|
|
|
@ -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_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_PACK_URL = (name) => `/api/pleroma/emoji/pack?name=${name}`
|
||||
const PLEROMA_EMOJI_PACKS_DL_REMOTE_URL = '/api/pleroma/emoji/packs/download'
|
||||
const PLEROMA_EMOJI_PACKS_URL = (page, pageSize) => `/api/v1/pleroma/emoji/packs?page=${page}&page_size=${pageSize}`
|
||||
const PLEROMA_EMOJI_PACK_URL = (name) => `/api/v1/pleroma/emoji/pack?name=${name}`
|
||||
const PLEROMA_EMOJI_PACKS_DL_REMOTE_URL = '/api/v1/pleroma/emoji/packs/download'
|
||||
const PLEROMA_EMOJI_PACKS_LS_REMOTE_URL =
|
||||
(url, page, pageSize) => `/api/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}`
|
||||
(url, page, pageSize) => `/api/v1/pleroma/emoji/packs/remote?url=${url}&page=${page}&page_size=${pageSize}`
|
||||
const PLEROMA_EMOJI_UPDATE_FILE_URL = (name) => `/api/v1/pleroma/emoji/packs/files?name=${name}`
|
||||
|
||||
const oldfetch = window.fetch
|
||||
|
||||
|
@ -1809,36 +1809,34 @@ const importEmojiFromFS = () => {
|
|||
}
|
||||
|
||||
const createEmojiPack = ({ name }) => {
|
||||
return fetch(PLEROMA_EMOJI_PACK_URL(name), { method: 'PUT' })
|
||||
return fetch(PLEROMA_EMOJI_PACK_URL(name), { method: 'POST' })
|
||||
}
|
||||
|
||||
const listEmojiPacks = () => {
|
||||
return fetch(PLEROMA_EMOJI_PACKS_URL(1, 25))
|
||||
const listEmojiPacks = ({ page, pageSize }) => {
|
||||
return fetch(PLEROMA_EMOJI_PACKS_URL(page, pageSize))
|
||||
}
|
||||
|
||||
const listRemoteEmojiPacks = ({ instance }) => {
|
||||
const listRemoteEmojiPacks = ({ instance, page, pageSize }) => {
|
||||
if (!instance.startsWith('http')) {
|
||||
instance = 'https://' + instance
|
||||
}
|
||||
|
||||
return fetch(
|
||||
PLEROMA_EMOJI_PACKS_LS_REMOTE_URL,
|
||||
PLEROMA_EMOJI_PACKS_LS_REMOTE_URL(instance, page, pageSize),
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ instance_address: instance })
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const downloadRemoteEmojiPack = ({ instance, packName, as }) => {
|
||||
if (as.trim() === '') {
|
||||
as = null
|
||||
}
|
||||
|
||||
return fetch(
|
||||
PLEROMA_EMOJI_PACKS_DL_REMOTE_URL,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
instance_address: instance, pack_name: packName, as
|
||||
url: instance, name: packName, as
|
||||
})
|
||||
}
|
||||
)
|
||||
|
@ -1850,7 +1848,7 @@ const saveEmojiPackMetadata = ({ name, newData }) => {
|
|||
{
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name, new_data: newData })
|
||||
body: JSON.stringify({ metadata: newData })
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -1863,7 +1861,7 @@ const addNewEmojiFile = ({ packName, file, shortcode, filename }) => {
|
|||
|
||||
return fetch(
|
||||
PLEROMA_EMOJI_UPDATE_FILE_URL(packName),
|
||||
{ method: 'POST', data }
|
||||
{ method: 'POST', body: data }
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue