forked from FoundKeyGang/FoundKey
feat: multiple emojis editing
This commit is contained in:
parent
b17726c9da
commit
1f2dab0a83
10 changed files with 428 additions and 139 deletions
|
@ -0,0 +1,39 @@
|
||||||
|
import $ from 'cafy';
|
||||||
|
import define from '../../../define';
|
||||||
|
import { ID } from '@/misc/cafy-id';
|
||||||
|
import { Emojis } from '@/models/index';
|
||||||
|
import { getConnection, In } from 'typeorm';
|
||||||
|
import { ApiError } from '../../../error';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['admin'],
|
||||||
|
|
||||||
|
requireCredential: true as const,
|
||||||
|
requireModerator: true,
|
||||||
|
|
||||||
|
params: {
|
||||||
|
ids: {
|
||||||
|
validator: $.arr($.type(ID)),
|
||||||
|
},
|
||||||
|
|
||||||
|
aliases: {
|
||||||
|
validator: $.arr($.str),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default define(meta, async (ps) => {
|
||||||
|
const emojis = await Emojis.find({
|
||||||
|
id: In(ps.ids),
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
await Emojis.update(emoji.id, {
|
||||||
|
updatedAt: new Date(),
|
||||||
|
aliases: [...new Set(emoji.aliases.concat(ps.aliases))],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await getConnection().queryResultCache!.remove(['meta_emojis']);
|
||||||
|
});
|
|
@ -0,0 +1,37 @@
|
||||||
|
import $ from 'cafy';
|
||||||
|
import define from '../../../define';
|
||||||
|
import { ID } from '@/misc/cafy-id';
|
||||||
|
import { Emojis } from '@/models/index';
|
||||||
|
import { getConnection, In } from 'typeorm';
|
||||||
|
import { insertModerationLog } from '@/services/insert-moderation-log';
|
||||||
|
import { ApiError } from '../../../error';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['admin'],
|
||||||
|
|
||||||
|
requireCredential: true as const,
|
||||||
|
requireModerator: true,
|
||||||
|
|
||||||
|
params: {
|
||||||
|
ids: {
|
||||||
|
validator: $.arr($.type(ID)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default define(meta, async (ps, me) => {
|
||||||
|
const emojis = await Emojis.find({
|
||||||
|
id: In(ps.ids),
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
await Emojis.delete(emoji.id);
|
||||||
|
|
||||||
|
await getConnection().queryResultCache!.remove(['meta_emojis']);
|
||||||
|
|
||||||
|
insertModerationLog(me, 'deleteEmoji', {
|
||||||
|
emoji: emoji,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
|
@ -37,7 +37,7 @@ export default define(meta, async (ps, me) => {
|
||||||
|
|
||||||
await getConnection().queryResultCache!.remove(['meta_emojis']);
|
await getConnection().queryResultCache!.remove(['meta_emojis']);
|
||||||
|
|
||||||
insertModerationLog(me, 'removeEmoji', {
|
insertModerationLog(me, 'deleteEmoji', {
|
||||||
emoji: emoji,
|
emoji: emoji,
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -0,0 +1,21 @@
|
||||||
|
import $ from 'cafy';
|
||||||
|
import define from '../../../define';
|
||||||
|
import { createImportCustomEmojisJob } from '@/queue/index';
|
||||||
|
import ms from 'ms';
|
||||||
|
import { ID } from '@/misc/cafy-id';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
secure: true,
|
||||||
|
requireCredential: true as const,
|
||||||
|
requireModerator: true,
|
||||||
|
params: {
|
||||||
|
fileId: {
|
||||||
|
validator: $.type(ID),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default define(meta, async (ps, user) => {
|
||||||
|
createImportCustomEmojisJob(user, ps.fileId);
|
||||||
|
});
|
|
@ -0,0 +1,39 @@
|
||||||
|
import $ from 'cafy';
|
||||||
|
import define from '../../../define';
|
||||||
|
import { ID } from '@/misc/cafy-id';
|
||||||
|
import { Emojis } from '@/models/index';
|
||||||
|
import { getConnection, In } from 'typeorm';
|
||||||
|
import { ApiError } from '../../../error';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['admin'],
|
||||||
|
|
||||||
|
requireCredential: true as const,
|
||||||
|
requireModerator: true,
|
||||||
|
|
||||||
|
params: {
|
||||||
|
ids: {
|
||||||
|
validator: $.arr($.type(ID)),
|
||||||
|
},
|
||||||
|
|
||||||
|
aliases: {
|
||||||
|
validator: $.arr($.str),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default define(meta, async (ps) => {
|
||||||
|
const emojis = await Emojis.find({
|
||||||
|
id: In(ps.ids),
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
await Emojis.update(emoji.id, {
|
||||||
|
updatedAt: new Date(),
|
||||||
|
aliases: emoji.aliases.filter(x => !ps.aliases.includes(x)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await getConnection().queryResultCache!.remove(['meta_emojis']);
|
||||||
|
});
|
|
@ -0,0 +1,35 @@
|
||||||
|
import $ from 'cafy';
|
||||||
|
import define from '../../../define';
|
||||||
|
import { ID } from '@/misc/cafy-id';
|
||||||
|
import { Emojis } from '@/models/index';
|
||||||
|
import { getConnection, In } from 'typeorm';
|
||||||
|
import { ApiError } from '../../../error';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['admin'],
|
||||||
|
|
||||||
|
requireCredential: true as const,
|
||||||
|
requireModerator: true,
|
||||||
|
|
||||||
|
params: {
|
||||||
|
ids: {
|
||||||
|
validator: $.arr($.type(ID)),
|
||||||
|
},
|
||||||
|
|
||||||
|
aliases: {
|
||||||
|
validator: $.arr($.str),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default define(meta, async (ps) => {
|
||||||
|
await Emojis.update({
|
||||||
|
id: In(ps.ids),
|
||||||
|
}, {
|
||||||
|
updatedAt: new Date(),
|
||||||
|
aliases: ps.aliases,
|
||||||
|
});
|
||||||
|
|
||||||
|
await getConnection().queryResultCache!.remove(['meta_emojis']);
|
||||||
|
});
|
|
@ -0,0 +1,35 @@
|
||||||
|
import $ from 'cafy';
|
||||||
|
import define from '../../../define';
|
||||||
|
import { ID } from '@/misc/cafy-id';
|
||||||
|
import { Emojis } from '@/models/index';
|
||||||
|
import { getConnection, In } from 'typeorm';
|
||||||
|
import { ApiError } from '../../../error';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['admin'],
|
||||||
|
|
||||||
|
requireCredential: true as const,
|
||||||
|
requireModerator: true,
|
||||||
|
|
||||||
|
params: {
|
||||||
|
ids: {
|
||||||
|
validator: $.arr($.type(ID)),
|
||||||
|
},
|
||||||
|
|
||||||
|
category: {
|
||||||
|
validator: $.optional.nullable.str,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default define(meta, async (ps) => {
|
||||||
|
await Emojis.update({
|
||||||
|
id: In(ps.ids),
|
||||||
|
}, {
|
||||||
|
updatedAt: new Date(),
|
||||||
|
category: ps.category,
|
||||||
|
});
|
||||||
|
|
||||||
|
await getConnection().queryResultCache!.remove(['meta_emojis']);
|
||||||
|
});
|
|
@ -95,7 +95,7 @@ export default defineComponent({
|
||||||
});
|
});
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
|
|
||||||
os.api('admin/emoji/remove', {
|
os.api('admin/emoji/delete', {
|
||||||
id: this.emoji.id
|
id: this.emoji.id
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.$emit('done', {
|
this.$emit('done', {
|
||||||
|
|
|
@ -6,11 +6,22 @@
|
||||||
<template #prefix><i class="fas fa-search"></i></template>
|
<template #prefix><i class="fas fa-search"></i></template>
|
||||||
<template #label>{{ $ts.search }}</template>
|
<template #label>{{ $ts.search }}</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkPagination ref="emojis" :pagination="pagination">
|
<MkSwitch v-model="selectMode" style="margin: 8px 0;">
|
||||||
|
<template #label>Select mode</template>
|
||||||
|
</MkSwitch>
|
||||||
|
<div v-if="selectMode" style="display: flex; gap: var(--margin); flex-wrap: wrap;">
|
||||||
|
<MkButton inline @click="selectAll">Select all</MkButton>
|
||||||
|
<MkButton inline @click="setCategoryBulk">Set category</MkButton>
|
||||||
|
<MkButton inline @click="addTagBulk">Add tag</MkButton>
|
||||||
|
<MkButton inline @click="removeTagBulk">Remove tag</MkButton>
|
||||||
|
<MkButton inline @click="setTagBulk">Set tag</MkButton>
|
||||||
|
<MkButton inline danger @click="delBulk">Delete</MkButton>
|
||||||
|
</div>
|
||||||
|
<MkPagination ref="emojisPaginationComponent" :pagination="pagination">
|
||||||
<template #empty><span>{{ $ts.noCustomEmojis }}</span></template>
|
<template #empty><span>{{ $ts.noCustomEmojis }}</span></template>
|
||||||
<template v-slot="{items}">
|
<template v-slot="{items}">
|
||||||
<div class="ldhfsamy">
|
<div class="ldhfsamy">
|
||||||
<button v-for="emoji in items" :key="emoji.id" class="emoji _panel _button" @click="edit(emoji)">
|
<button v-for="emoji in items" :key="emoji.id" class="emoji _panel _button" :class="{ selected: selectedEmojis.includes(emoji.id) }" @click="selectMode ? toggleSelect(emoji) : edit(emoji)">
|
||||||
<img :src="emoji.url" class="img" :alt="emoji.name"/>
|
<img :src="emoji.url" class="img" :alt="emoji.name"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="name _monospace">{{ emoji.name }}</div>
|
<div class="name _monospace">{{ emoji.name }}</div>
|
||||||
|
@ -32,7 +43,7 @@
|
||||||
<template #label>{{ $ts.host }}</template>
|
<template #label>{{ $ts.host }}</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</FormSplit>
|
</FormSplit>
|
||||||
<MkPagination ref="remoteEmojis" :pagination="remotePagination">
|
<MkPagination :pagination="remotePagination">
|
||||||
<template #empty><span>{{ $ts.noCustomEmojis }}</span></template>
|
<template #empty><span>{{ $ts.noCustomEmojis }}</span></template>
|
||||||
<template v-slot="{items}">
|
<template v-slot="{items}">
|
||||||
<div class="ldhfsamy">
|
<div class="ldhfsamy">
|
||||||
|
@ -51,148 +62,213 @@
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { computed, defineComponent, toRef } from 'vue';
|
import { computed, defineComponent, ref, toRef } from 'vue';
|
||||||
import MkButton from '@/components/ui/button.vue';
|
import MkButton from '@/components/ui/button.vue';
|
||||||
import MkInput from '@/components/form/input.vue';
|
import MkInput from '@/components/form/input.vue';
|
||||||
import MkPagination from '@/components/ui/pagination.vue';
|
import MkPagination from '@/components/ui/pagination.vue';
|
||||||
import MkTab from '@/components/tab.vue';
|
import MkTab from '@/components/tab.vue';
|
||||||
|
import MkSwitch from '@/components/form/switch.vue';
|
||||||
import FormSplit from '@/components/form/split.vue';
|
import FormSplit from '@/components/form/split.vue';
|
||||||
import { selectFiles } from '@/scripts/select-file';
|
import { selectFile, selectFiles } from '@/scripts/select-file';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import * as symbols from '@/symbols';
|
import * as symbols from '@/symbols';
|
||||||
|
import { i18n } from '@/i18n';
|
||||||
|
|
||||||
export default defineComponent({
|
const emojisPaginationComponent = ref<InstanceType<typeof MkPagination>>();
|
||||||
components: {
|
|
||||||
MkTab,
|
|
||||||
MkButton,
|
|
||||||
MkInput,
|
|
||||||
MkPagination,
|
|
||||||
FormSplit,
|
|
||||||
},
|
|
||||||
|
|
||||||
emits: ['info'],
|
const tab = ref('local');
|
||||||
|
const query = ref(null);
|
||||||
|
const queryRemote = ref(null);
|
||||||
|
const host = ref(null);
|
||||||
|
const selectMode = ref(false);
|
||||||
|
const selectedEmojis = ref<string[]>([]);
|
||||||
|
|
||||||
data() {
|
const pagination = {
|
||||||
return {
|
endpoint: 'admin/emoji/list',
|
||||||
[symbols.PAGE_INFO]: computed(() => ({
|
limit: 30,
|
||||||
title: this.$ts.customEmojis,
|
params: computed(() => ({
|
||||||
icon: 'fas fa-laugh',
|
query: (query.value && query.value !== '') ? query.value : null,
|
||||||
bg: 'var(--bg)',
|
})),
|
||||||
actions: [{
|
};
|
||||||
asFullButton: true,
|
|
||||||
icon: 'fas fa-plus',
|
|
||||||
text: this.$ts.addEmoji,
|
|
||||||
handler: this.add,
|
|
||||||
}, {
|
|
||||||
icon: 'fas fa-ellipsis-h',
|
|
||||||
handler: this.menu,
|
|
||||||
}],
|
|
||||||
tabs: [{
|
|
||||||
active: this.tab === 'local',
|
|
||||||
title: this.$ts.local,
|
|
||||||
onClick: () => { this.tab = 'local'; },
|
|
||||||
}, {
|
|
||||||
active: this.tab === 'remote',
|
|
||||||
title: this.$ts.remote,
|
|
||||||
onClick: () => { this.tab = 'remote'; },
|
|
||||||
},]
|
|
||||||
})),
|
|
||||||
tab: 'local',
|
|
||||||
query: null,
|
|
||||||
queryRemote: null,
|
|
||||||
host: '',
|
|
||||||
pagination: {
|
|
||||||
endpoint: 'admin/emoji/list',
|
|
||||||
limit: 30,
|
|
||||||
params: computed(() => ({
|
|
||||||
query: (this.query && this.query !== '') ? this.query : null
|
|
||||||
}))
|
|
||||||
},
|
|
||||||
remotePagination: {
|
|
||||||
endpoint: 'admin/emoji/list-remote',
|
|
||||||
limit: 30,
|
|
||||||
params: computed(() => ({
|
|
||||||
query: (this.queryRemote && this.queryRemote !== '') ? this.queryRemote : null,
|
|
||||||
host: (this.host && this.host !== '') ? this.host : null
|
|
||||||
}))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async mounted() {
|
const remotePagination = {
|
||||||
this.$emit('info', toRef(this, symbols.PAGE_INFO));
|
endpoint: 'admin/emoji/list-remote',
|
||||||
},
|
limit: 30,
|
||||||
|
params: computed(() => ({
|
||||||
|
query: (queryRemote.value && queryRemote.value !== '') ? queryRemote.value : null,
|
||||||
|
host: (host.value && host.value !== '') ? host.value : null,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
methods: {
|
const selectAll = () => {
|
||||||
async add(e) {
|
if (selectedEmojis.value.length > 0) {
|
||||||
const files = await selectFiles(e.currentTarget || e.target, null);
|
selectedEmojis.value = [];
|
||||||
|
} else {
|
||||||
const promise = Promise.all(files.map(file => os.api('admin/emoji/add', {
|
selectedEmojis.value = emojisPaginationComponent.value.items.map(item => item.id);
|
||||||
fileId: file.id,
|
|
||||||
})));
|
|
||||||
promise.then(() => {
|
|
||||||
this.$refs.emojis.reload();
|
|
||||||
});
|
|
||||||
os.promiseDialog(promise);
|
|
||||||
},
|
|
||||||
|
|
||||||
edit(emoji) {
|
|
||||||
os.popup(import('./emoji-edit-dialog.vue'), {
|
|
||||||
emoji: emoji
|
|
||||||
}, {
|
|
||||||
done: result => {
|
|
||||||
if (result.updated) {
|
|
||||||
this.$refs.emojis.replaceItem(item => item.id === emoji.id, {
|
|
||||||
...emoji,
|
|
||||||
...result.updated
|
|
||||||
});
|
|
||||||
} else if (result.deleted) {
|
|
||||||
this.$refs.emojis.removeItem(item => item.id === emoji.id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}, 'closed');
|
|
||||||
},
|
|
||||||
|
|
||||||
im(emoji) {
|
|
||||||
os.apiWithDialog('admin/emoji/copy', {
|
|
||||||
emojiId: emoji.id,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
remoteMenu(emoji, ev) {
|
|
||||||
os.popupMenu([{
|
|
||||||
type: 'label',
|
|
||||||
text: ':' + emoji.name + ':',
|
|
||||||
}, {
|
|
||||||
text: this.$ts.import,
|
|
||||||
icon: 'fas fa-plus',
|
|
||||||
action: () => { this.im(emoji) }
|
|
||||||
}], ev.currentTarget || ev.target);
|
|
||||||
},
|
|
||||||
|
|
||||||
menu(ev) {
|
|
||||||
os.popupMenu([{
|
|
||||||
icon: 'fas fa-download',
|
|
||||||
text: this.$ts.export,
|
|
||||||
action: async () => {
|
|
||||||
os.api('export-custom-emojis', {
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
os.alert({
|
|
||||||
type: 'info',
|
|
||||||
text: this.$ts.exportRequested,
|
|
||||||
});
|
|
||||||
}).catch((e) => {
|
|
||||||
os.alert({
|
|
||||||
type: 'error',
|
|
||||||
text: e.message,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}], ev.currentTarget || ev.target);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleSelect = (emoji) => {
|
||||||
|
if (selectedEmojis.value.includes(emoji.id)) {
|
||||||
|
selectedEmojis.value = selectedEmojis.value.filter(x => x !== emoji.id);
|
||||||
|
} else {
|
||||||
|
selectedEmojis.value.push(emoji.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const add = async (ev: MouseEvent) => {
|
||||||
|
const files = await selectFiles(ev.currentTarget || ev.target, null);
|
||||||
|
|
||||||
|
const promise = Promise.all(files.map(file => os.api('admin/emoji/add', {
|
||||||
|
fileId: file.id,
|
||||||
|
})));
|
||||||
|
promise.then(() => {
|
||||||
|
emojisPaginationComponent.value.reload();
|
||||||
|
});
|
||||||
|
os.promiseDialog(promise);
|
||||||
|
};
|
||||||
|
|
||||||
|
const edit = (emoji) => {
|
||||||
|
os.popup(import('./emoji-edit-dialog.vue'), {
|
||||||
|
emoji: emoji
|
||||||
|
}, {
|
||||||
|
done: result => {
|
||||||
|
if (result.updated) {
|
||||||
|
emojisPaginationComponent.value.replaceItem(item => item.id === emoji.id, {
|
||||||
|
...emoji,
|
||||||
|
...result.updated
|
||||||
|
});
|
||||||
|
} else if (result.deleted) {
|
||||||
|
emojisPaginationComponent.value.removeItem(item => item.id === emoji.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}, 'closed');
|
||||||
|
};
|
||||||
|
|
||||||
|
const im = (emoji) => {
|
||||||
|
os.apiWithDialog('admin/emoji/copy', {
|
||||||
|
emojiId: emoji.id,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const remoteMenu = (emoji, ev: MouseEvent) => {
|
||||||
|
os.popupMenu([{
|
||||||
|
type: 'label',
|
||||||
|
text: ':' + emoji.name + ':',
|
||||||
|
}, {
|
||||||
|
text: i18n.locale.import,
|
||||||
|
icon: 'fas fa-plus',
|
||||||
|
action: () => { im(emoji) }
|
||||||
|
}], ev.currentTarget || ev.target);
|
||||||
|
};
|
||||||
|
|
||||||
|
const menu = (ev: MouseEvent) => {
|
||||||
|
os.popupMenu([{
|
||||||
|
icon: 'fas fa-download',
|
||||||
|
text: i18n.locale.export,
|
||||||
|
action: async () => {
|
||||||
|
os.api('export-custom-emojis', {
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
os.alert({
|
||||||
|
type: 'info',
|
||||||
|
text: i18n.locale.exportRequested,
|
||||||
|
});
|
||||||
|
}).catch((e) => {
|
||||||
|
os.alert({
|
||||||
|
type: 'error',
|
||||||
|
text: e.message,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}], ev.currentTarget || ev.target);
|
||||||
|
};
|
||||||
|
|
||||||
|
const setCategoryBulk = async () => {
|
||||||
|
const { canceled, result } = await os.inputText({
|
||||||
|
title: 'Category',
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
await os.apiWithDialog('admin/emoji/set-category-bulk', {
|
||||||
|
ids: selectedEmojis.value,
|
||||||
|
category: result,
|
||||||
|
});
|
||||||
|
emojisPaginationComponent.value.reload();
|
||||||
|
};
|
||||||
|
|
||||||
|
const addTagBulk = async () => {
|
||||||
|
const { canceled, result } = await os.inputText({
|
||||||
|
title: 'Tag',
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
await os.apiWithDialog('admin/emoji/add-aliases-bulk', {
|
||||||
|
ids: selectedEmojis.value,
|
||||||
|
aliases: result.split(' '),
|
||||||
|
});
|
||||||
|
emojisPaginationComponent.value.reload();
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeTagBulk = async () => {
|
||||||
|
const { canceled, result } = await os.inputText({
|
||||||
|
title: 'Tag',
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
await os.apiWithDialog('admin/emoji/remove-aliases-bulk', {
|
||||||
|
ids: selectedEmojis.value,
|
||||||
|
aliases: result.split(' '),
|
||||||
|
});
|
||||||
|
emojisPaginationComponent.value.reload();
|
||||||
|
};
|
||||||
|
|
||||||
|
const setTagBulk = async () => {
|
||||||
|
const { canceled, result } = await os.inputText({
|
||||||
|
title: 'Tag',
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
await os.apiWithDialog('admin/emoji/set-aliases-bulk', {
|
||||||
|
ids: selectedEmojis.value,
|
||||||
|
aliases: result.split(' '),
|
||||||
|
});
|
||||||
|
emojisPaginationComponent.value.reload();
|
||||||
|
};
|
||||||
|
|
||||||
|
const delBulk = async () => {
|
||||||
|
const { canceled } = await os.confirm({
|
||||||
|
type: 'warning',
|
||||||
|
text: i18n.locale.deleteConfirm,
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
await os.apiWithDialog('admin/emoji/delete-bulk', {
|
||||||
|
ids: selectedEmojis.value,
|
||||||
|
});
|
||||||
|
emojisPaginationComponent.value.reload();
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
[symbols.PAGE_INFO]: computed(() => ({
|
||||||
|
title: i18n.locale.customEmojis,
|
||||||
|
icon: 'fas fa-laugh',
|
||||||
|
bg: 'var(--bg)',
|
||||||
|
actions: [{
|
||||||
|
asFullButton: true,
|
||||||
|
icon: 'fas fa-plus',
|
||||||
|
text: i18n.locale.addEmoji,
|
||||||
|
handler: add,
|
||||||
|
}, {
|
||||||
|
icon: 'fas fa-ellipsis-h',
|
||||||
|
handler: menu,
|
||||||
|
}],
|
||||||
|
tabs: [{
|
||||||
|
active: tab.value === 'local',
|
||||||
|
title: i18n.locale.local,
|
||||||
|
onClick: () => { tab.value = 'local'; },
|
||||||
|
}, {
|
||||||
|
active: tab.value === 'remote',
|
||||||
|
title: i18n.locale.remote,
|
||||||
|
onClick: () => { tab.value = 'remote'; },
|
||||||
|
},]
|
||||||
|
})),
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -212,11 +288,16 @@ export default defineComponent({
|
||||||
> .emoji {
|
> .emoji {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 12px;
|
padding: 11px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
border: solid 1px var(--panel);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: var(--accent);
|
border-color: var(--inputBorderHover);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
border-color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
> .img {
|
> .img {
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<MkStickyContainer>
|
<MkStickyContainer>
|
||||||
<template #header><MkHeader v-if="childInfo && !childInfo.hideHeader" :info="childInfo"/></template>
|
<template #header><MkHeader v-if="childInfo && !childInfo.hideHeader" :info="childInfo"/></template>
|
||||||
<component :is="component" :key="page" v-bind="pageProps" @info="onInfo"/>
|
<component :is="component" :ref="el => pageChanged(el)" :key="page" v-bind="pageProps"/>
|
||||||
</MkStickyContainer>
|
</MkStickyContainer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -66,7 +66,9 @@ export default defineComponent({
|
||||||
const narrow = ref(false);
|
const narrow = ref(false);
|
||||||
const view = ref(null);
|
const view = ref(null);
|
||||||
const el = ref(null);
|
const el = ref(null);
|
||||||
const onInfo = (viewInfo) => {
|
const pageChanged = (page) => {
|
||||||
|
if (page == null) return;
|
||||||
|
const viewInfo = page[symbols.PAGE_INFO];
|
||||||
if (isRef(viewInfo)) {
|
if (isRef(viewInfo)) {
|
||||||
watch(viewInfo, () => {
|
watch(viewInfo, () => {
|
||||||
childInfo.value = viewInfo.value;
|
childInfo.value = viewInfo.value;
|
||||||
|
@ -311,7 +313,7 @@ export default defineComponent({
|
||||||
narrow,
|
narrow,
|
||||||
view,
|
view,
|
||||||
el,
|
el,
|
||||||
onInfo,
|
pageChanged,
|
||||||
childInfo,
|
childInfo,
|
||||||
pageProps,
|
pageProps,
|
||||||
component,
|
component,
|
||||||
|
|
Loading…
Reference in a new issue