Merge branch 'feature/update-and-move-emoji-packs' into 'master'

Redesign emoji packs and move it to settings

See merge request pleroma/admin-fe!54
This commit is contained in:
feld 2019-10-23 13:54:41 +00:00
commit 07a5c005b6
16 changed files with 611 additions and 576 deletions

View file

@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed
- moves emoji pack configuration from the main menu to settings tab, redesigns it and fixes bugs
- `mailerEnabled` must be set to `true` in order to require password reset (password reset currently only works via email)
- remove fetching initial data for configuring server settings
- Actions in users module (ActivateUsers, AddRight, DeactivateUsers, DeleteRight, DeleteUsers) now accept an array of users instead of one user

View file

@ -312,7 +312,56 @@ export default {
rateLimiters: 'Rate limiters',
database: 'Database',
other: 'Other',
success: 'Settings changed successfully!'
success: 'Settings changed successfully!',
emojiPacks: 'Emoji packs',
reloadEmoji: 'Reload emoji',
importPacks: 'Import packs from the server filesystem',
importEmojiTooltip: 'Importing from the filesystem will scan the directories and import those without pack.json but with emoji.txt or without neither',
localPacks: 'Local packs',
refreshLocalPacks: 'Refresh local packs',
createLocalPack: 'Create a new local pack',
packs: 'Packs',
remotePacks: 'Remote packs',
remoteInstanceAddress: 'Remote instance address',
refreshRemote: 'Refresh remote packs',
sharePack: 'Share pack',
homepage: 'Homepage',
description: 'Description',
license: 'License',
fallbackSrc: 'Fallback source',
fallbackSrcSha: 'Fallback source SHA',
savePackMetadata: 'Save pack metadata',
addNewEmoji: 'Add new emoji to the pack',
shortcode: 'Shortcode',
uploadFile: 'Upload a file',
customFilename: 'Custom filename',
optional: 'optional',
customFilenameDesc: 'Custom file name (optional)',
url: 'URL',
required: 'required',
clickToUpload: 'Click to upload',
showPackContents: 'Show pack contents',
manageEmoji: 'Manage existing emoji',
file: 'File',
update: 'Update',
remove: 'Remove',
selectLocalPack: 'Select the local pack to copy to',
localPack: 'Local pack',
specifyShortcode: 'Specify a custom shortcode',
specifyFilename: 'Specify a custom filename',
leaveEmptyShortcode: 'leave empty to use the same shortcode',
leaveEmptyFilename: 'leave empty to use the same filename',
copy: 'Copy',
copyToLocalPack: 'Copy to local pack',
thisWillDownload: 'This will download the',
downloadToCurrentInstance: 'pack to the current instance under the name',
canBeChanged: 'can be changed below',
willBeUsable: 'It will then be usable and shareable from the current instance',
downloadPack: 'Download pack',
deletePack: 'Delete pack',
downloadSharedPack: 'Download shared pack to current instance',
downloadAsOptional: 'Download as (optional)',
downloadPackArchive: 'Download pack archive'
},
invites: {
inviteTokens: 'Invite tokens',

View file

@ -63,20 +63,6 @@ const moderationLog = {
]
}
const emojiPacksDisabled = disabledFeatures.includes('emoji-packs')
const emojiPacks = {
path: '/emoji-packs',
component: Layout,
children: [
{
path: 'index',
component: () => import('@/views/emoji-packs/index'),
name: 'Emoji packs',
meta: { title: 'emoji-packs', icon: 'settings', noCache: true }
}
]
}
export const constantRouterMap = [
{
path: '/redirect',
@ -144,7 +130,6 @@ export const asyncRouterMap = [
...(invitesDisabled ? [] : [invites]),
...(moderationLogDisabled ? [] : [moderationLog]),
...(settingsDisabled ? [] : [settings]),
...(emojiPacksDisabled ? [] : [emojiPacks]),
{
path: '/users/:id',
component: Layout,

View file

@ -12,7 +12,7 @@ import user from './modules/user'
import userProfile from './modules/userProfile'
import users from './modules/users'
import getters from './getters'
import emoji_packs from './modules/emoji_packs.js'
import emojiPacks from './modules/emojiPacks.js'
Vue.use(Vuex)
@ -29,7 +29,7 @@ const store = new Vuex.Store({
user,
userProfile,
users,
emoji_packs
emojiPacks
},
getters
})

View file

@ -7,7 +7,7 @@ import {
deletePack,
savePackMetadata,
importFromFS,
updatePackFile } from '@/api/emoji_packs'
updatePackFile } from '@/api/emojiPacks'
import { Message } from 'element-ui'

View file

@ -14,9 +14,10 @@ service.interceptors.response.use(
console.log(`Error ${error}`)
if (error.response) {
// If there's an "error" property in the json, use it
const edata = error.response.data.error ? error.response.data.error : error.response.data
errorMessage = `${error.message} - ${edata}`
errorMessage = !error.response.headers['content-type'].includes('application/json')
? `${error.message}`
: `${error.message} - ${edata}`
} else {
errorMessage = error
}

View file

@ -1,218 +0,0 @@
<template>
<div>
<h2>{{ name }}</h2>
<prop-editing-row name="Share pack">
<el-switch v-model="share" :disabled="!isLocal" />
</prop-editing-row>
<prop-editing-row name="Homepage">
<el-input v-if="isLocal" v-model="homepage" />
<el-input v-else :value="homepage" />
</prop-editing-row>
<prop-editing-row name="Description">
<el-input v-if="isLocal" :rows="2" v-model="description" type="textarea" />
<el-input v-else :rows="2" :value="description" type="textarea" />
</prop-editing-row>
<prop-editing-row name="License">
<el-input v-if="isLocal" v-model="license" />
<el-input v-else :value="license" />
</prop-editing-row>
<prop-editing-row name="Fallback source">
<el-input v-if="isLocal" v-model="fallbackSrc" />
<el-input v-else :value="fallbackSrc" />
</prop-editing-row>
<prop-editing-row v-if="fallbackSrc && fallbackSrc.trim() !== ''" name="Fallback source SHA">
{{ pack.pack["fallback-src-sha256"] }}
</prop-editing-row>
<el-button v-if="isLocal" type="success" @click="savePackMetadata">Save pack metadata</el-button>
<el-collapse v-model="shownPackEmoji" class="contents-collapse">
<el-collapse-item :name="name" title="Show pack contents">
<new-emoji-uploader v-if="isLocal" :pack-name="name" class="new-emoji-uploader" />
<h4>Manage existing emoji</h4>
<single-emoji-editor
v-for="(file, ename) in pack.files"
:key="ename"
:host="host"
:pack-name="name"
:name="ename"
:file="file"
:is-local="isLocal" />
</el-collapse-item>
</el-collapse>
<div v-if="!isLocal" class="shared-pack-dl-box">
<div>
This will download the "{{ name }}" pack to the current instance under the name
"{{ downloadSharedAs.trim() === '' ? name : downloadSharedAs }}" (can be changed below).
It will then be usable and shareable from the current instance.
</div>
<el-button type="primary" @click="downloadFromInstance">
Download shared pack to current instance
</el-button>
<el-input v-model="downloadSharedAs" class="dl-as-input" placeholder="Download as (optional)" />
</div>
<el-link
v-if="pack.pack['can-download']"
:href="`//${host}/api/pleroma/emoji/packs/${name}/download_shared`"
type="primary"
target="_blank">
Download pack archive
</el-link>
<div v-if="isLocal" class="pack-actions">
<el-button type="danger" @click="deletePack">
Delete the local pack
</el-button>
</div>
</div>
</template>
<style>
.shared-pack-dl-box {
margin: 1em;
}
.dl-as-input {
margin: 1em;
max-width: 30%;
}
.contents-collapse {
margin: 1em;
}
.pack-actions {
margin-top: 1em;
}
.new-emoji-uploader {
margin-bottom: 3em;
}
</style>
<script>
import PropEditingRow from './PropertyEditingRow.vue'
import SingleEmojiEditor from './SingleEmojiEditor.vue'
import NewEmojiUploader from './NewEmojiUploader.vue'
export default {
components: { PropEditingRow, SingleEmojiEditor, NewEmojiUploader },
props: {
name: {
type: String,
required: true
},
pack: {
type: Object,
required: true
},
host: {
type: String,
required: true
},
isLocal: {
type: Boolean,
required: true
}
},
data() {
return {
shownPackEmoji: [],
downloadSharedAs: ''
}
},
computed: {
share: {
get() { return this.pack.pack['share-files'] },
set(value) {
this.$store.dispatch(
'UpdateLocalPackVal',
{ name: this.name, key: 'share-files', value }
)
}
},
homepage: {
get() { return this.pack.pack['homepage'] },
set(value) {
this.$store.dispatch(
'UpdateLocalPackVal',
{ name: this.name, key: 'homepage', value }
)
}
},
description: {
get() { return this.pack.pack['description'] },
set(value) {
this.$store.dispatch(
'UpdateLocalPackVal',
{ name: this.name, key: 'description', value }
)
}
},
license: {
get() { return this.pack.pack['license'] },
set(value) {
this.$store.dispatch(
'UpdateLocalPackVal',
{ name: this.name, key: 'license', value }
)
}
},
fallbackSrc: {
get() { return this.pack.pack['fallback-src'] },
set(value) {
if (value.trim() !== '') {
this.$store.dispatch(
'UpdateLocalPackVal',
{ name: this.name, key: 'fallback-src', value }
)
} else {
this.$store.dispatch(
'UpdateLocalPackVal',
{ name: this.name, key: 'fallback-src', value: null }
)
this.$store.dispatch(
'UpdateLocalPackVal',
{ name: this.name, key: 'fallback-src-sha256', value: null }
)
}
}
}
},
methods: {
downloadFromInstance() {
this.$store.dispatch(
'DownloadFrom',
{ instanceAddress: this.host, packName: this.name, as: this.downloadSharedAs }
).then(() => this.$store.dispatch('ReloadEmoji'))
.then(() => this.$store.dispatch('SetLocalEmojiPacks'))
},
deletePack() {
this.$confirm('This will delete the pack, are you sure?', 'Warning', {
confirmButtonText: 'Yes, delete the pack',
cancelButtonText: 'No, leave it be',
type: 'warning'
}).then(() => {
this.$store.dispatch('DeletePack', { name: this.name })
.then(() => this.$store.dispatch('ReloadEmoji'))
.then(() => this.$store.dispatch('SetLocalEmojiPacks'))
}).catch(() => {})
},
savePackMetadata() {
this.$store.dispatch('SavePackMetadata', { packName: this.name })
}
}
}
</script>

View file

@ -1,93 +0,0 @@
<template>
<div>
<h4>Add new emoji to the pack</h4>
<el-row :gutter="20">
<el-col :span="4" class="new-emoji-col">
<el-input v-model="shortcode" placeholder="Shortcode" />
</el-col>
<el-col :span="8">
<div>
<h5>Upload a file</h5>
</div>
File name
<el-input v-model="customFileName" size="mini" placeholder="Custom file name (optional)"/>
<input ref="fileUpload" type="file" accept="image/*" >
<div class="or">
or
</div>
<div>
<h5>Enter a URL</h5>
</div>
<el-input v-model="imageUploadURL" placeholder="Image URL" />
<small>
(If both are filled, the file is used)
</small>
</el-col>
<el-col :span="4" class="new-emoji-col">
<el-button :disabled="shortcode.trim() == ''" @click="upload">Upload</el-button>
</el-col>
</el-row>
</div>
</template>
<style>
.new-emoji-col {
margin-top: 8em;
}
.or {
margin: 1em;
}
</style>
<script>
export default {
props: {
packName: {
type: String,
required: true
}
},
data() {
return {
shortcode: '',
imageUploadURL: '',
customFileName: ''
}
},
methods: {
upload() {
let file = null
if (this.$refs.fileUpload.files.length > 0) {
file = this.$refs.fileUpload.files[0]
} else if (this.imageUploadURL.trim() !== '') {
file = this.imageUploadURL
}
if (file !== null) {
this.$store.dispatch('UpdateAndSavePackFile', {
action: 'add',
packName: this.packName,
shortcode: this.shortcode,
file: file,
fileName: this.customFileName
}).then(() => {
this.shortcode = ''
this.imageUploadURL = ''
this.$store.dispatch('ReloadEmoji')
})
}
}
}
}
</script>

View file

@ -1,27 +0,0 @@
<template>
<el-row :gutter="20" class="prop-row">
<el-col :span="4">
<b>{{ name }}</b>
</el-col>
<el-col :span="10">
<slot/>
</el-col>
</el-row>
</template>
<style>
.prop-row {
margin-bottom: 1em;
}
</style>
<script>
export default {
props: {
name: {
type: String,
required: true
}
}
}
</script>

View file

@ -1,151 +0,0 @@
<template>
<el-container class="emoji-packs-container">
<el-header>
<h1>
Emoji packs
</h1>
</el-header>
<el-row class="local-packs-actions">
<el-button type="primary" @click="reloadEmoji">
Reload emoji
</el-button>
<el-tooltip effects="dark" content="Importing from the filesystem will scan the directories and import those without pack.json but with emoji.txt or without neither" placement="bottom">
<el-button type="success" @click="importFromFS">
Import packs from the server filesystem
</el-button>
</el-tooltip>
</el-row>
<el-tabs v-model="activeName">
<el-tab-pane label="Local packs" name="local">
<div>
Local packs can be viewed and downloaded for backup here.
</div>
<div class="local-packs-actions">
<el-popover
v-model="createNewPackVisible"
placement="bottom"
trigger="click">
<el-input v-model="newPackName" placeholder="Name" />
<el-button
:disabled="newPackName.trim() === ''"
class="create-pack-button"
type="success"
@click="createLocalPack" >
Create
</el-button>
<el-button slot="reference" type="success">
Create a new local pack
</el-button>
</el-popover>
<el-button type="primary" @click="refreshLocalPacks">
Refresh local packs
</el-button>
</div>
<div v-for="(pack, name) in $store.state.emoji_packs.localPacks" :key="name">
<emoji-pack :name="name" :pack="pack" :host="$store.getters.authHost" :is-local="true" />
<el-divider />
</div>
</el-tab-pane>
<el-tab-pane label="Remote packs" name="remote">
<el-input
v-model="remoteInstanceAddress"
class="remote-instance-input"
placeholder="Remote instance address" />
<el-button type="primary" @click="refreshRemotePacks">
Refresh remote packs
</el-button>
<div v-for="(pack, name) in $store.state.emoji_packs.remotePacks" :key="name">
<emoji-pack :name="name" :pack="pack" :host="remoteInstanceAddress" :is-local="false" />
<el-divider />
</div>
</el-tab-pane>
</el-tabs>
</el-container>
</template>
<style>
.emoji-packs-container {
margin: 22px 0 0 15px;
}
.local-packs-actions {
margin-top: 1em;
margin-bottom: 1em;
}
.remote-instance-input {
max-width: 10%;
}
.create-pack-button {
margin-top: 1em;
}
</style>
<script>
import EmojiPack from './components/EmojiPack'
export default {
components: { EmojiPack },
data() {
return {
activeName: 'local',
remoteInstanceAddress: '',
downloadFromState: null,
newPackName: '',
createNewPackVisible: false
}
},
mounted() {
this.refreshLocalPacks()
},
methods: {
createLocalPack() {
this.createNewPackVisible = false
this.$store.dispatch('CreatePack', { name: this.newPackName })
.then(() => {
this.newPackName = ''
this.$store.dispatch('SetLocalEmojiPacks')
this.$store.dispatch('ReloadEmoji')
})
},
refreshLocalPacks() {
this.$store.dispatch('SetLocalEmojiPacks')
},
refreshRemotePacks() {
this.$store.dispatch('SetRemoteEmojiPacks', { remoteInstance: this.remoteInstanceAddress })
},
reloadEmoji() {
this.$store.dispatch('ReloadEmoji')
},
importFromFS() {
this.$store.dispatch('ImportFromFS')
.then(() => {
this.$store.dispatch('SetLocalEmojiPacks')
this.$store.dispatch('ReloadEmoji')
})
}
}
}
</script>

View file

@ -0,0 +1,257 @@
<template>
<el-collapse-item :title="name" :name="name" class="has-background">
<el-form v-if="isLocal" label-width="120px" label-position="left" size="small" class="emoji-pack-metadata">
<el-form-item :label="$t('settings.sharePack')">
<el-switch v-model="share" />
</el-form-item>
<el-form-item :label="$t('settings.homepage')">
<el-input v-model="homepage" />
</el-form-item>
<el-form-item :label="$t('settings.description')">
<el-input v-model="description" type="textarea" />
</el-form-item>
<el-form-item :label="$t('settings.license')">
<el-input v-model="license" />
</el-form-item>
<el-form-item :label="$t('settings.fallbackSrc')">
<el-input v-model="fallbackSrc" />
</el-form-item>
<el-form-item
v-if="fallbackSrc && fallbackSrc.trim() !== ''"
:label="$t('settings.fallbackSrcSha')">
{{ pack.pack["fallback-src-sha256"] }}
</el-form-item>
<el-form-item class="save-pack-button">
<el-button type="primary" @click="savePackMetadata">{{ $t('settings.savePackMetadata') }}</el-button>
<el-button @click="deletePack">{{ $t('settings.deletePack') }}</el-button>
</el-form-item>
<el-form-item>
<el-link
v-if="pack.pack['can-download']"
:href="`//${host}/api/pleroma/emoji/packs/${name}/download_shared`"
:underline="false"
type="primary"
target="_blank">
<el-button class="download-archive">{{ $t('settings.downloadPackArchive') }}</el-button>
</el-link>
</el-form-item>
</el-form>
<el-form v-if="!isLocal" label-width="120px" label-position="left" size="small" class="emoji-pack-metadata">
<el-form-item :label="$t('settings.sharePack')">
<el-switch v-model="share" disabled />
</el-form-item>
<el-form-item v-if="homepage" :label="$t('settings.homepage')">
<span>{{ homepage }}</span>
</el-form-item>
<el-form-item v-if="description" :label="$t('settings.description')">
<span>{{ description }}</span>
</el-form-item>
<el-form-item v-if="license" :label="$t('settings.license')">
<span>{{ license }}</span>
</el-form-item>
<el-form-item v-if="fallbackSrc" :label="$t('settings.fallbackSrc')">
<span>{{ fallbackSrc }}</span>
</el-form-item>
<el-form-item
v-if="fallbackSrc && fallbackSrc.trim() !== ''"
:label="$t('settings.fallbackSrcSha')">
{{ pack.pack["fallback-src-sha256"] }}
</el-form-item>
<el-form-item>
<el-link
v-if="pack.pack['can-download']"
:href="`//${host}/api/pleroma/emoji/packs/${name}/download_shared`"
:underline="false"
type="primary"
target="_blank">
<el-button class="download-archive">{{ $t('settings.downloadPackArchive') }}</el-button>
</el-link>
</el-form-item>
</el-form>
<el-collapse v-model="showPackContent" class="contents-collapse">
<el-collapse-item v-if="isLocal" :title="$t('settings.addNewEmoji')" name="addEmoji" class="no-background">
<new-emoji-uploader :pack-name="name"/>
</el-collapse-item>
<el-collapse-item v-if="Object.keys(pack.files).length > 0" :title="$t('settings.manageEmoji')" name="manageEmoji" class="no-background">
<single-emoji-editor
v-for="(file, ename) in pack.files"
:key="ename"
:host="host"
:pack-name="name"
:name="ename"
:file="file"
:is-local="isLocal" />
</el-collapse-item>
<el-collapse-item v-if="!isLocal" :title="$t('settings.downloadPack')" name="downloadPack" class="no-background">
<p>
{{ $t('settings.thisWillDownload') }} "{{ name }}" {{ $t('settings.downloadToCurrentInstance') }}
"{{ downloadSharedAs.trim() === '' ? name : downloadSharedAs }}" ({{ $t('settings.canBeChanged') }}).
{{ $t('settings.willBeUsable') }}.
</p>
<div class="download-shared-pack">
<el-input v-model="downloadSharedAs" :placeholder="$t('settings.downloadAsOptional')"/>
<el-button type="primary" class="download-shared-pack-button" @click="downloadFromInstance">
{{ $t('settings.downloadSharedPack') }}
</el-button>
</div>
</el-collapse-item>
</el-collapse>
</el-collapse-item>
</template>
<script>
import SingleEmojiEditor from './SingleEmojiEditor.vue'
import NewEmojiUploader from './NewEmojiUploader.vue'
export default {
components: { SingleEmojiEditor, NewEmojiUploader },
props: {
name: {
type: String,
required: true
},
pack: {
type: Object,
required: true
},
host: {
type: String,
required: true
},
isLocal: {
type: Boolean,
required: true
}
},
data() {
return {
showPackContent: [],
downloadSharedAs: ''
}
},
computed: {
share: {
get() { return this.pack.pack['share-files'] },
set(value) {
this.$store.dispatch(
'UpdateLocalPackVal',
{ name: this.name, key: 'share-files', value }
)
}
},
homepage: {
get() { return this.pack.pack['homepage'] },
set(value) {
this.$store.dispatch(
'UpdateLocalPackVal',
{ name: this.name, key: 'homepage', value }
)
}
},
description: {
get() { return this.pack.pack['description'] },
set(value) {
this.$store.dispatch(
'UpdateLocalPackVal',
{ name: this.name, key: 'description', value }
)
}
},
license: {
get() { return this.pack.pack['license'] },
set(value) {
this.$store.dispatch(
'UpdateLocalPackVal',
{ name: this.name, key: 'license', value }
)
}
},
fallbackSrc: {
get() { return this.pack.pack['fallback-src'] },
set(value) {
if (value.trim() !== '') {
this.$store.dispatch(
'UpdateLocalPackVal',
{ name: this.name, key: 'fallback-src', value }
)
} else {
this.$store.dispatch(
'UpdateLocalPackVal',
{ name: this.name, key: 'fallback-src', value: null }
)
this.$store.dispatch(
'UpdateLocalPackVal',
{ name: this.name, key: 'fallback-src-sha256', value: null }
)
}
}
}
},
methods: {
downloadFromInstance() {
this.$store.dispatch(
'DownloadFrom',
{ instanceAddress: this.host, packName: this.name, as: this.downloadSharedAs }
).then(() => this.$store.dispatch('ReloadEmoji'))
.then(() => this.$store.dispatch('SetLocalEmojiPacks'))
},
deletePack() {
this.$confirm('This will delete the pack, are you sure?', 'Warning', {
confirmButtonText: 'Yes, delete the pack',
cancelButtonText: 'No, leave it be',
type: 'warning'
}).then(() => {
this.$store.dispatch('DeletePack', { name: this.name })
.then(() => this.$store.dispatch('ReloadEmoji'))
.then(() => this.$store.dispatch('SetLocalEmojiPacks'))
}).catch(() => {})
},
savePackMetadata() {
this.$store.dispatch('SavePackMetadata', { packName: this.name })
}
}
}
</script>
<style rel='stylesheet/scss' lang='scss'>
.download-archive {
width: 250px
}
.download-shared-pack {
display: flex;
margin-bottom: 10px;
}
.download-shared-pack-button {
margin-left: 10px;
}
.el-collapse-item__content {
padding-bottom: 0;
}
.el-collapse-item__header {
height: 36px;
font-size: 14px;
font-weight: 700;
color: #606266;
}
.emoji-pack-card {
margin-top: 5px;
}
.emoji-pack-metadata {
.el-form-item {
margin-bottom: 10px;
}
}
.has-background .el-collapse-item__header {
background: #f6f6f6;
}
.no-background .el-collapse-item__header {
background: white;
}
.save-pack-button {
margin-bottom: 5px
}
</style>

View file

@ -0,0 +1,90 @@
<template>
<el-form label-width="130px" label-position="left" size="small">
<el-form-item :label="$t('settings.shortcode')">
<el-input v-model="shortcode" :placeholder="$t('settings.required')"/>
</el-form-item>
<el-form-item :label="$t('settings.customFilename')">
<el-input v-model="customFileName" :placeholder="$t('settings.optional')"/>
</el-form-item>
<el-form-item :label="$t('settings.uploadFile')">
<div class="upload-file-url">
<el-input v-model="imageUploadURL" :placeholder="$t('settings.url')"/>
<el-button :disabled="shortcodePresent" type="primary" class="upload-button" @click="uploadEmoji">{{ $t('settings.upload') }}</el-button>
</div>
<div class="upload-container">
<p class="text">or</p>
<el-upload
:http-request="uploadEmoji"
:multiple="false"
:show-file-list="false"
action="add">
<el-button :disabled="shortcodePresent" type="primary">{{ $t('settings.clickToUpload') }}</el-button>
</el-upload>
</div>
</el-form-item>
</el-form>
</template>
<style>
.add-new-emoji {
height: 36px;
font-size: 14px;
font-weight: 700;
color: #606266;
}
.text {
line-height: 20px;
margin-right: 15px
}
.upload-container {
display: flex;
align-items: baseline;
}
.upload-button {
margin-left: 10px;
}
.upload-file-url {
display: flex;
justify-content: space-between
}
</style>
<script>
export default {
props: {
packName: {
type: String,
required: true
}
},
data() {
return {
shortcode: '',
imageUploadURL: '',
customFileName: ''
}
},
computed: {
shortcodePresent() {
return this.shortcode.trim() === ''
}
},
methods: {
uploadEmoji({ file }) {
this.$store.dispatch('UpdateAndSavePackFile', {
action: 'add',
packName: this.packName,
shortcode: this.shortcode,
file: file || this.imageUploadURL,
fileName: this.customFileName
}).then(() => {
this.shortcode = ''
this.imageUploadURL = ''
this.customFileName = ''
this.$store.dispatch('ReloadEmoji')
})
}
}
}
</script>

View file

@ -1,71 +1,50 @@
<template>
<el-row :gutter="20">
<el-col :span="4">
<el-input v-if="isLocal" v-model="modifyingName" placeholder="Name/Shortcode" />
<el-input v-else :value="modifyingName" placeholder="Name/Shortcode" />
</el-col>
<el-col :span="6">
<el-input v-if="isLocal" v-model="modifyingFile" placeholder="File"/>
<el-input v-else :value="modifyingFile" placeholder="File"/>
</el-col>
<div>
<div v-if="isLocal" class="emoji-container">
<img
:src="addressOfEmojiInPack(host, packName, file)"
class="emoji-preview-img">
<el-input v-model="emojiName" :placeholder="$t('settings.shortcode')" class="emoji-info"/>
<el-input v-model="emojiFile" :placeholder="$t('settings.file')" class="emoji-info"/>
<div class="emoji-buttons">
<el-button type="primary" class="emoji-button" @click="update">{{ $t('settings.update') }}</el-button>
<el-button class="emoji-button" @click="remove">{{ $t('settings.remove') }}</el-button>
</div>
</div>
<el-col v-if="isLocal" :span="2">
<el-button type="primary" @click="update">Update</el-button>
</el-col>
<el-col v-if="isLocal" :span="2">
<el-button type="danger" @click="remove">Remove</el-button>
</el-col>
<el-col v-if="!isLocal" :span="4">
<el-popover v-model="copyToLocalVisible" placement="bottom">
<p>Select the local pack to copy to</p>
<el-select v-model="copyToLocalPackName" placeholder="Local pack">
<div v-if="!isLocal" class="emoji-container">
<img
:src="addressOfEmojiInPack(host, packName, file)"
class="emoji-preview-img">
<el-input :value="emojiName" :placeholder="$t('settings.shortcode')" class="emoji-info"/>
<el-input :value="emojiFile" :placeholder="$t('settings.file')" class="emoji-info"/>
<el-popover v-model="copyPopoverVisible" placement="left-start" popper-class="copy-popover">
<p>{{ $t('settings.selectLocalPack') }}</p>
<el-select v-model="copyToLocalPackName" :placeholder="$t('settings.localPack')">
<el-option
v-for="(_pack, name) in $store.state.emoji_packs.localPacks"
v-for="(_pack, name) in localPacks"
:key="name"
:label="name"
:value="name" />
</el-select>
<p>Specify a custom shortcode (leave empty to use the same shortcode)</p>
<el-input v-model="copyToShortcode" placeholder="Shortcode (optional)" />
<p>Specify a custom filename (leavy empty to use the same filename)</p>
<el-input v-model="copyToFilename" placeholder="Filename (optional)" />
<p>{{ $t('settings.specifyShortcode') }}</p>
<el-input v-model="copyToShortcode" :placeholder="$t('settings.leaveEmptyShortcode')"/>
<p>{{ $t('settings.specifyFilename') }}</p>
<el-input v-model="copyToFilename" :placeholder="$t('settings.leaveEmptyFilename')"/>
<el-button
:disabled="!copyToLocalPackName"
type="success"
type="primary"
class="copy-to-local-button"
@click="copyToLocal">Copy</el-button>
<el-button slot="reference" type="primary">Copy to local pack...</el-button>
@click="copyToLocal">{{ $t('settings.copy') }}</el-button>
<el-button slot="reference" type="primary" class="emoji-button">{{ $t('settings.copyToLocalPack') }}</el-button>
</el-popover>
</el-col>
<el-col :span="2">
<img
:src="addressOfEmojiInPack(host, packName, file)"
class="emoji-preview-img">
</el-col>
</el-row>
</div>
</div>
</template>
<style>
.emoji-preview-img {
max-width: 5em;
}
.copy-to-local-button {
margin-top: 2em;
float: right;
}
</style>
<script>
import { addressOfEmojiInPack } from '@/api/emoji_packs'
import { addressOfEmojiInPack } from '@/api/emojiPacks'
export default {
props: {
host: {
@ -89,33 +68,33 @@ export default {
required: true
}
},
data() {
return {
newName: null,
newFile: null,
copyToLocalPackName: null,
copyToLocalVisible: false,
copyPopoverVisible: false,
copyToShortcode: '',
copyToFilename: ''
}
},
computed: {
modifyingName: {
emojiName: {
get() {
// Return a modified name if it was actually modified, otherwise return the old name
// Return a modified name if it was modified, otherwise return the old name
return this.newName !== null ? this.newName : this.name
},
set(val) { this.newName = val }
},
modifyingFile: {
emojiFile: {
get() {
// Return a modified name if it was actually modified, otherwise return the old name
// Return a modified name if it was modified, otherwise return the old name
return this.newFile !== null ? this.newFile : this.file
},
set(val) { this.newFile = val }
},
localPacks() {
return this.$store.state.emojiPacks.localPacks
}
},
methods: {
@ -124,8 +103,8 @@ export default {
action: 'update',
packName: this.packName,
oldName: this.name,
newName: this.modifyingName,
newFilename: this.modifyingFile
newName: this.emojiName,
newFilename: this.emojiFile
}).then(() => {
this.newName = null
this.newFile = null
@ -151,7 +130,6 @@ export default {
})
})
},
copyToLocal() {
this.$store.dispatch('UpdateAndSavePackFile', {
action: 'add',
@ -168,8 +146,35 @@ export default {
this.$store.dispatch('ReloadEmoji')
})
},
addressOfEmojiInPack
}
}
</script>
<style>
.copy-popover {
width: 330px
}
.emoji-button {
margin-left: 10px
}
.emoji-buttons {
min-width: 210px
}
.emoji-container {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.emoji-preview-img {
max-width: 5em;
}
.emoji-info {
margin-left: 10px
}
.copy-to-local-button {
margin-top: 12px;
float: right;
}
</style>

View file

@ -0,0 +1,132 @@
<template>
<div>
<div class="button-container">
<el-button type="primary" @click="reloadEmoji">{{ $t('settings.reloadEmoji') }}</el-button>
<el-tooltip :content="$t('settings.importEmojiTooltip')" effects="dark" placement="bottom">
<el-button type="primary" @click="importFromFS">
{{ $t('settings.importPacks') }}
</el-button>
</el-tooltip>
</div>
<div class="line"/>
<el-form :label-width="labelWidth">
<el-form-item :label="$t('settings.localPacks')">
<el-button type="primary" @click="refreshLocalPacks">{{ $t('settings.refreshLocalPacks') }}</el-button>
</el-form-item>
<el-form-item :label="$t('settings.createLocalPack')">
<div class="create-pack">
<el-input v-model="newPackName" :placeholder="$t('users.name')" />
<el-button
:disabled="newPackName.trim() === ''"
class="create-pack-button"
@click="createLocalPack">
{{ $t('users.create') }}
</el-button>
</div>
</el-form-item>
<el-form-item v-if="Object.keys(localPacks).length > 0" :label="$t('settings.packs')">
<el-collapse v-for="(pack, name) in localPacks" :key="name" v-model="activeLocalPack">
<emoji-pack :name="name" :pack="pack" :host="$store.getters.authHost" :is-local="true" />
</el-collapse>
</el-form-item>
<div class="line"/>
<el-form-item :label="$t('settings.remotePacks')">
<div class="create-pack">
<el-input
v-model="remoteInstanceAddress"
:placeholder="$t('settings.remoteInstanceAddress')" />
<el-button
:disabled="remoteInstanceAddress.trim() === ''"
class="create-pack-button"
@click="refreshRemotePacks">
{{ $t('settings.refreshRemote') }}
</el-button>
</div>
</el-form-item>
<el-form-item v-if="Object.keys(remotePacks).length > 0" :label="$t('settings.packs')">
<el-collapse v-for="(pack, name) in remotePacks" :key="name" v-model="activeRemotePack">
<emoji-pack :name="name" :pack="pack" :host="$store.getters.authHost" :is-local="false" />
</el-collapse>
</el-form-item>
</el-form>
</div>
</template>
<script>
import EmojiPack from './components/EmojiPack'
export default {
components: { EmojiPack },
data() {
return {
remoteInstanceAddress: '',
newPackName: '',
activeLocalPack: [],
activeRemotePack: []
}
},
computed: {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '210px'
},
localPacks() {
return this.$store.state.emojiPacks.localPacks
},
remotePacks() {
return this.$store.state.emojiPacks.remotePacks
}
},
mounted() {
this.refreshLocalPacks()
},
methods: {
createLocalPack() {
this.$store.dispatch('CreatePack', { name: this.newPackName })
.then(() => {
this.newPackName = ''
this.$store.dispatch('SetLocalEmojiPacks')
this.$store.dispatch('ReloadEmoji')
})
},
refreshLocalPacks() {
this.$store.dispatch('SetLocalEmojiPacks')
},
refreshRemotePacks() {
this.$store.dispatch('SetRemoteEmojiPacks', { remoteInstance: this.remoteInstanceAddress })
},
reloadEmoji() {
this.$store.dispatch('ReloadEmoji')
},
importFromFS() {
this.$store.dispatch('ImportFromFS')
.then(() => {
this.$store.dispatch('SetLocalEmojiPacks')
this.$store.dispatch('ReloadEmoji')
})
}
}
}
</script>
<style rel='stylesheet/scss' lang='scss'>
.button-container {
margin: 0 0 22px 20px;
}
.create-pack {
display: flex;
justify-content: space-between
}
.create-pack-button {
margin-left: 10px;
}
.line {
width: 100%;
height: 0;
border: 1px solid #eee;
margin-bottom: 22px;
}
</style>

View file

@ -23,6 +23,9 @@
<el-tab-pane :label="$t('settings.endpoint')">
<endpoint/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.emojiPacks')">
<emoji-packs/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.frontend')">
<frontend/>
</el-tab-pane>
@ -71,9 +74,10 @@
<script>
import { ActivityPub, Authentication, AutoLinker, Captcha, Database, Endpoint, Esshd, Frontend, Gopher, Http, Instance, JobQueue, Logger, Mailer, MediaProxy, Metadata, Mrf, Other, RateLimiters, Upload, WebPush } from './components'
import EmojiPacks from '../emojiPacks/index'
export default {
components: { ActivityPub, Authentication, AutoLinker, Captcha, Database, Endpoint, Esshd, Frontend, Gopher, Http, Instance, JobQueue, Logger, Mailer, MediaProxy, Metadata, Mrf, Other, RateLimiters, Upload, WebPush },
components: { ActivityPub, Authentication, AutoLinker, Captcha, Database, Endpoint, EmojiPacks, Esshd, Frontend, Gopher, Http, Instance, JobQueue, Logger, Mailer, MediaProxy, Metadata, Mrf, Other, RateLimiters, Upload, WebPush },
computed: {
isMobile() {
return this.$store.state.app.device === 'mobile'