多分動くと思うからリリースしようぜ

This commit is contained in:
mattyatea 2023-12-23 10:44:01 +09:00
parent 68b48bc16f
commit 2a9ddf2bc8
16 changed files with 161 additions and 433 deletions

View file

@ -1,214 +0,0 @@
<template>
<MkPagination ref="emojisDraftPaginationComponent" :pagination="paginationDraft">
<template #empty><span>{{ i18n.ts.noCustomEmojis }}</span></template>
<template #default="{items}">
<div class="ldhfsamy">
<template v-for="emoji in items" :key="emoji.id">
<div class="emoji _panel">
<div class="img">
<div class="imgLight"><img :src="emoji.url" :alt="emoji.name"/></div>
<div class="imgDark"><img :src="emoji.url" :alt="emoji.name"/></div>
</div>
<div class="info">
<div class="name">{{ i18n.ts.name }}: {{ emoji.name }}</div>
<div class="category">{{ i18n.ts.category }}:{{ emoji.category }}</div>
<div class="aliases">{{ i18n.ts.tags }}:{{ emoji.aliases.join(' ') }}</div>
<div class="license">{{ i18n.ts.license }}:{{ emoji.license }}</div>
</div>
<div class="edit-button">
<MkButton primary class="edit" @click="editDraft(emoji)">
{{ i18n.ts.edit }}
</MkButton>
<MkButton class="draft" @click="undrafted(emoji)">
{{ i18n.ts.undrafted }}
</MkButton>
<MkButton danger class="delete" @click="deleteDraft(emoji)">
{{ i18n.ts.delete }}
</MkButton>
</div>
</div>
</template>
</div>
</template>
</MkPagination>
</template>
<script lang="ts" setup>
import { computed, defineAsyncComponent, ref, shallowRef } from 'vue';
import MkPagination from '@/components/MkPagination.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import MkButton from '@/components/MkButton.vue';
const emojisDraftPaginationComponent = shallowRef<InstanceType<typeof MkPagination>>();
const query = ref(null);
const paginationDraft = {
endpoint: 'admin/emoji/list' as const,
limit: 30,
params: computed(() => ({
query: (query.value && query.value !== '') ? query.value : null,
draft: true,
})),
};
const editDraft = (emoji) => {
os.popup(defineAsyncComponent(() => import('@/components/MkEmojiEditDialog.vue')), {
emoji: emoji,
isRequest: false,
}, {
done: result => {
if (result.updated) {
emojisDraftPaginationComponent.value.updateItem(result.updated.id, (oldEmoji: any) => ({
...oldEmoji,
...result.updated,
}));
emojisDraftPaginationComponent.value.reload();
} else if (result.deleted) {
emojisDraftPaginationComponent.value.removeItem((item) => item.id === emoji.id);
emojisDraftPaginationComponent.value.reload();
}
},
}, 'closed');
};
async function undrafted(emoji) {
const { canceled } = await os.confirm({
type: 'warning',
text: i18n.t('undraftAreYouSure', { x: emoji.name }),
});
if (canceled) return;
await os.api('admin/emoji/update', {
id: emoji.id,
name: emoji.name,
category: emoji.category,
aliases: emoji.aliases,
license: emoji.license,
draft: false,
isSensitive: emoji.isSensitive,
localOnly: emoji.localOnly,
roleIdsThatCanBeUsedThisEmojiAsReaction: emoji.roleIdsThatCanBeUsedThisEmojiAsReaction,
});
emojisDraftPaginationComponent.value.removeItem((item) => item.id === emoji.id);
emojisDraftPaginationComponent.value.reload();
}
async function deleteDraft(emoji) {
const { canceled } = await os.confirm({
type: 'warning',
text: i18n.t('removeAreYouSure', { x: emoji.name }),
});
if (canceled) return;
os.api('admin/emoji/delete', {
id: emoji.id,
}).then(() => {
emojisDraftPaginationComponent.value.removeItem((item) => item.id === emoji.id);
emojisDraftPaginationComponent.value.reload();
});
}
</script>
<style lang="scss" scoped>
.empty {
margin: var(--margin);
}
.ldhfsamy {
> .emoji {
align-items: center;
padding: 11px;
text-align: left;
border: solid 1px var(--panel);
margin: 10px;
> .img {
display: grid;
grid-row: 1;
grid-column: 1/ span 2;
grid-template-columns: 50% 50%;
place-content: center;
place-items: center;
> .imgLight {
display: grid;
grid-column: 1;
background-color: #fff;
margin-bottom: 12px;
> img {
max-height: 64px;
max-width: 100%;
}
}
> .imgDark {
display: grid;
grid-column: 2;
background-color: #000;
margin-bottom: 12px;
> img {
max-height: 64px;
max-width: 100%;
}
}
}
> .info {
display: grid;
grid-row: 2;
grid-template-rows: 30px 30px 30px;
> .name {
grid-row: 1;
text-overflow: ellipsis;
overflow: hidden;
}
> .category {
grid-row: 2;
text-overflow: ellipsis;
overflow: hidden;
}
> .aliases {
grid-row: 3;
text-overflow: ellipsis;
overflow: hidden;
}
> .license {
grid-row: 4;
text-overflow: ellipsis;
overflow: hidden;
}
}
> .edit-button {
display: grid;
grid-template-rows: 42px;
margin-top: 6px;
> .edit {
grid-row: 1;
width: 100%;
margin: 6px 0;
}
> .draft {
grid-row: 2;
width: 100%;
margin: 6px 0;
}
> .delete {
grid-row: 3;
width: 100%;
margin: 6px 0;
}
}
}
}
</style>

View file

@ -48,8 +48,8 @@ import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
import MkPagination from '@/components/MkPagination.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
const emojisPaginationComponent = shallowRef<InstanceType<typeof MkPagination>>();
@ -96,13 +96,6 @@ const setlocalOnlyBulk = async () => {
});
emojisPaginationComponent.value.reload();
};
const selectAll = () => {
if (selectedEmojis.value.length > 0) {
selectedEmojis.value = [];
} else {
selectedEmojis.value = Array.from(emojisPaginationComponent.value.items.values(), item => item.id);
}
};
const toggleSelect = (emoji) => {

View file

@ -63,8 +63,6 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInfo warn>{{ i18n.ts.rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn }}</MkInfo>
</div>
</MkFolder>
<MkSwitch v-model="isSensitive">isSensitive</MkSwitch>
<MkSwitch v-model="localOnly">{{ i18n.ts.localOnly }}</MkSwitch>
<MkSwitch v-model="isSensitive">{{ i18n.ts.isSensitive }}</MkSwitch>
<MkSwitch v-model="localOnly">{{ i18n.ts.localOnly }}</MkSwitch>
<MkSwitch v-model="isNotifyIsHome">
@ -86,7 +84,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
import { computed, watch } from 'vue';
import {computed, ref, watch} from 'vue';
import * as Misskey from 'misskey-js';
import { DriveFile } from 'misskey-js/built/entities.js';
import MkModalWindow from '@/components/MkModalWindow.vue';
@ -106,25 +104,24 @@ const props = defineProps<{
isRequest: boolean,
}>();
let dialog = $ref(null);
let name: string = $ref(props.emoji ? props.emoji.name : '');
let category: string = $ref(props.emoji ? props.emoji.category : '');
let aliases: string = $ref(props.emoji ? props.emoji.aliases.join(' ') : '');
let license: string = $ref(props.emoji ? (props.emoji.license ?? '') : '');
let isSensitive = $ref(props.emoji ? props.emoji.isSensitive : false);
let localOnly = $ref(props.emoji ? props.emoji.localOnly : false);
let roleIdsThatCanBeUsedThisEmojiAsReaction = $ref((props.emoji && props.emoji.roleIdsThatCanBeUsedThisEmojiAsReaction) ? props.emoji.roleIdsThatCanBeUsedThisEmojiAsReaction : []);
let rolesThatCanBeUsedThisEmojiAsReaction = $ref([]);
let file = $ref<Misskey.entities.DriveFile>();
let chooseFile: DriveFile|null = $ref(null);
let isRequest = $ref(props.isRequest ?? false);
watch($$(roleIdsThatCanBeUsedThisEmojiAsReaction), async () => {
rolesThatCanBeUsedThisEmojiAsReaction = (await Promise.all(roleIdsThatCanBeUsedThisEmojiAsReaction.map((id) => os.api('admin/roles/show', { roleId: id }).catch(() => null)))).filter(x => x != null);
let dialog = ref(null);
let name = ref(props.emoji ? props.emoji.name : '');
let category = ref(props.emoji ? props.emoji.category : '');
let aliases = ref(props.emoji ? props.emoji.aliases.join(' ') : '');
let license = ref(props.emoji ? (props.emoji.license ?? '') : '');
let isSensitive = ref(props.emoji ? props.emoji.isSensitive : false);
let localOnly = ref(props.emoji ? props.emoji.localOnly : false);
let roleIdsThatCanBeUsedThisEmojiAsReaction = ref((props.emoji && props.emoji.roleIdsThatCanBeUsedThisEmojiAsReaction) ? props.emoji.roleIdsThatCanBeUsedThisEmojiAsReaction : []);
let rolesThatCanBeUsedThisEmojiAsReaction = ref([]);
let file = ref<Misskey.entities.DriveFile>();
let isRequest = ref(props.isRequest ?? false);
watch((roleIdsThatCanBeUsedThisEmojiAsReaction), async () => {
rolesThatCanBeUsedThisEmojiAsReaction.value = (await Promise.all(roleIdsThatCanBeUsedThisEmojiAsReaction.value.map((id) => os.api('admin/roles/show', { roleId: id }).catch(() => null)))).filter(x => x != null);
}, { immediate: true });
const imgUrl = computed(() => file ? file.url : props.emoji && !isRequest ? `/emoji/${props.emoji.name}.webp` : props.emoji && props.emoji.url ? props.emoji.url : null);
const isNotifyIsHome = ref(props.emoji ? props.emoji.isNotifyIsHome : false);
const imgUrl = computed(() => file.value ? file.value.url : props.emoji && !isRequest.value ? `/emoji/${props.emoji.name}.webp` : props.emoji && props.emoji.url ? props.emoji.url : null);
const validation = computed(() => {
return name.match(/^[a-zA-Z0-9_]+$/) && imgUrl.value != null;
return name.value.match(/^[a-zA-Z0-9_]+$/) && imgUrl.value != null;
});
const emit = defineEmits<{
(ev: 'done', v: { deleted?: boolean; updated?: any; created?: any }): void,
@ -132,45 +129,44 @@ const emit = defineEmits<{
}>();
async function changeImage(ev) {
file = await selectFile(ev.currentTarget ?? ev.target, null);
const candidate = file.name.replace(/\.(.+)$/, '');
file.value = await selectFile(ev.currentTarget ?? ev.target, null);
const candidate = file.value.name.replace(/\.(.+)$/, '');
if (candidate.match(/^[a-z0-9_]+$/)) {
name = candidate;
name.value = candidate;
}
}
async function addRole() {
const roles = await os.api('admin/roles/list');
const currentRoleIds = rolesThatCanBeUsedThisEmojiAsReaction.map(x => x.id);
const currentRoleIds = rolesThatCanBeUsedThisEmojiAsReaction.value.map(x => x.id);
const { canceled, result: role } = await os.select({
items: roles.filter(r => r.isPublic).filter(r => !currentRoleIds.includes(r.id)).map(r => ({ text: r.name, value: r })),
});
if (canceled) return;
rolesThatCanBeUsedThisEmojiAsReaction.push(role);
rolesThatCanBeUsedThisEmojiAsReaction.value.push(role);
}
async function removeRole(role, ev) {
rolesThatCanBeUsedThisEmojiAsReaction = rolesThatCanBeUsedThisEmojiAsReaction.filter(x => x.id !== role.id);
rolesThatCanBeUsedThisEmojiAsReaction.value = rolesThatCanBeUsedThisEmojiAsReaction.value.filter(x => x.id !== role.id);
}
async function done() {
const params = {
name,
category: category === '' ? null : category,
aliases: aliases.replace(' ', ' ').split(' ').filter(x => x !== ''),
license: license === '' ? null : license,
Request: isRequest,
isSensitive,
localOnly,
roleIdsThatCanBeUsedThisEmojiAsReaction: rolesThatCanBeUsedThisEmojiAsReaction.map(x => x.id),
};
if (file) {
params.fileId = file.id;
}
name: name.value,
category: category.value === '' ? null : category.value,
aliases: aliases.value.replace(' ', ' ').split(' ').filter(x => x !== ''),
license: license.value === '' ? null : license.value,
Request: isRequest.value,
isSensitive: isSensitive.value,
localOnly: localOnly.value,
roleIdsThatCanBeUsedThisEmojiAsReaction: rolesThatCanBeUsedThisEmojiAsReaction.value.map(x => x.id),
};
if (file.value) {
params.fileId = file.value.id;
}
if (props.emoji) {
if (isRequest) {
await os.apiWithDialog('admin/emoji/update-request', {
@ -191,7 +187,7 @@ async function done() {
},
});
dialog.close();
dialog.value.close();
} else {
const created = isRequest
? await os.apiWithDialog('admin/emoji/add-request', params)
@ -201,7 +197,7 @@ async function done() {
created: created,
});
dialog.close();
dialog.value.close();
}
}
@ -218,7 +214,7 @@ async function del() {
emit('done', {
deleted: true,
});
dialog.close();
dialog.value.close();
});
}
</script>

View file

@ -244,7 +244,6 @@ if (darkMode.value && gamingMode.value == true) {
}
watch(darkMode, () => {
console.log(gaming)
if (darkMode.value && gamingMode.value == true) {
gaming.value = 'dark';
} else if (!darkMode.value && gamingMode.value == true) {

View file

@ -32,8 +32,6 @@ import XButton from '@/components/MkSwitch.button.vue';
import {defaultStore} from "@/store.js";
const gamingType = computed(defaultStore.makeGetterSetter('gamingType'));
console.log(gamingType.value)
const props = defineProps<{
modelValue: boolean | Ref<boolean>;
disabled?: boolean;

View file

@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer v-if="tab === 'emojis'" :contentMax="1000" :marginMin="20">
<MkButton v-if="$i && ($i.isModerator || $i.policies.canManageCustomEmojis)" primary link to="/custom-emojis-manager">{{ i18n.ts.manageCustomEmojis }}</MkButton>
<MkButton v-if="$i && (!$i.isModerator && $i.policies.canRequestCustomEmojis)" primary @click="edit">{{ i18n.ts.requestCustomEmojis }}</MkButton>
<MkButton v-if="$i && (!$i.isModerator || $i.policies.canRequestCustomEmojis)" primary @click="edit">{{ i18n.ts.requestCustomEmojis }}</MkButton>
<div class="query" style="margin-top: 10px;">
<MkInput v-model="q" class="" :placeholder="i18n.ts.search" autocapitalize="off">
@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
import { watch, defineAsyncComponent, ref } from 'vue';
import {watch, defineAsyncComponent, ref, computed} from 'vue';
import * as Misskey from 'misskey-js';
import XEmoji from './emojis.emoji.vue';
import MkButton from '@/components/MkButton.vue';
@ -57,10 +57,10 @@ import * as os from '@/os';
import { $i } from '@/account.js';
import { definePageMetadata } from '@/scripts/page-metadata';
let tab = $ref('emojis');
const headerActions = $computed(() => []);
let tab = ref('emojis');
const headerActions = computed(() => []);
const headerTabs = $computed(() => [{
const headerTabs = computed(() => [{
key: 'emojis',
title: i18n.ts.list,
}, {
@ -70,29 +70,29 @@ const headerTabs = $computed(() => [{
definePageMetadata(ref({}));
let q = $ref('');
let searchEmojis = $ref<Misskey.entities.CustomEmoji[]>(null);
let selectedTags = $ref(new Set());
let q = ref('');
let searchEmojis = ref<Misskey.entities.CustomEmoji[]>(null);
let selectedTags = ref(new Set());
const requestEmojis = await os.apiGet('emoji-requests');
function search() {
if ((q === '' || q == null) && selectedTags.size === 0) {
searchEmojis = null;
if ((q.value === '' || q.value == null) && selectedTags.value.size === 0) {
searchEmojis.value = null;
return;
}
if (selectedTags.size === 0) {
const queryarry = q.match(/\:([a-z0-9_]*)\:/g);
if (selectedTags.value.size === 0) {
const queryarry = q.value.match(/\:([a-z0-9_]*)\:/g);
if (queryarry) {
searchEmojis = customEmojis.value.filter(emoji =>
searchEmojis.value = customEmojis.value.filter(emoji =>
queryarry.includes(`:${emoji.name}:`),
);
} else {
searchEmojis = customEmojis.value.filter(emoji => emoji.name.includes(q) || emoji.aliases.includes(q));
searchEmojis.value = customEmojis.value.filter(emoji => emoji.name.includes(q.value) || emoji.aliases.includes(q));
}
} else {
searchEmojis = customEmojis.value.filter(emoji => (emoji.name.includes(q) || emoji.aliases.includes(q)) && [...selectedTags].every(t => emoji.aliases.includes(t)));
searchEmojis.value = customEmojis.value.filter(emoji => (emoji.name.includes(q.value) || emoji.aliases.includes(q)) && [...selectedTags].every(t => emoji.aliases.includes(t)));
}
}
@ -106,11 +106,11 @@ const edit = () => {
}, 'closed');
};
watch($$(q), () => {
watch((q), () => {
search();
});
watch($$(selectedTags), () => {
watch((selectedTags), () => {
search();
}, { deep: true });

View file

@ -48,6 +48,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #prefix><i class="ti ti-key"></i></template>
<template #label>ApiBase</template>
</MkInput>
<MkSwitch v-model="requestEmojiAllOk">
絵文字の申請全部許可
</MkSwitch>
</div>
</FormSuspense>
</MkSpacer>
@ -69,6 +72,7 @@ const enableServerMachineStats = ref<boolean>(false);
const enableIdenticonGeneration = ref<boolean>(false);
const enableChartsForRemoteUser = ref<boolean>(false);
const enableChartsForFederatedInstances = ref<boolean>(false);
const requestEmojiAllOk = ref(false)
let DiscordWebhookUrl = ref(null);
let EmojiBotToken= ref(null);
let ApiBase= ref(null)
@ -78,6 +82,7 @@ async function init() {
enableIdenticonGeneration.value = meta.enableIdenticonGeneration;
enableChartsForRemoteUser.value = meta.enableChartsForRemoteUser;
enableChartsForFederatedInstances.value = meta.enableChartsForFederatedInstances;
requestEmojiAllOk.value = meta.requestEmojiAllOk;
DiscordWebhookUrl.value = meta.DiscordWebhookUrl;
EmojiBotToken.value = meta.EmojiBotToken;
ApiBase.value = meta.ApiBase;
@ -88,6 +93,7 @@ function save() {
enableServerMachineStats: enableServerMachineStats.value,
enableIdenticonGeneration: enableIdenticonGeneration.value,
enableChartsForRemoteUser: enableChartsForRemoteUser.value,
requestEmojiAllOk: requestEmojiAllOk.value,
enableChartsForFederatedInstances: enableChartsForFederatedInstances.value,
DiscordWebhookUrl:DiscordWebhookUrl.value,
EmojiBotToken:EmojiBotToken.value,

View file

@ -37,7 +37,7 @@ import { definePageMetadata } from '@/scripts/page-metadata';
const tab = ref('request');
const add = async (ev: MouseEvent) => {
os.popup(defineAsyncComponent(() => import('./emoji-edit-dialog.vue')), {
os.popup(defineAsyncComponent(() => import('../components/MkEmojiEditDialog.vue')), {
}, {
done: result => {
//TODO: emit
@ -91,7 +91,7 @@ const menu = (ev: MouseEvent) => {
}], ev.currentTarget ?? ev.target);
};
const headerActions = $computed(() => [{
const headerActions = computed(() => [{
asFullButton: true,
icon: 'ti ti-plus',
text: i18n.ts.addEmoji,
@ -101,7 +101,7 @@ const headerActions = $computed(() => [{
handler: menu,
}]);
const headerTabs = $computed(() => [{
const headerTabs = computed(() => [{
key: 'request',
title: i18n.ts.requestingEmojis,
}, {