mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-05-23 04:04:08 +02:00
refactor(frontend): os.select, MkSelectのitem指定をオブジェクトによる定義に統一し、型を狭める (#16475)
* refactor(frontend): MkSelectのitem指定をオブジェクトによる定義に統一 * fix * spdx * fix * fix os.select * fix lint * add comment * fix * fix: os.select対応漏れを修正 * fix * fix * fix: MkSelectのmodelに対する型チェックを厳格化 * fix * fix * fix * Update packages/frontend/src/components/MkEmbedCodeGenDialog.vue Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> * fix * fix types * fix * fix * Update packages/frontend/src/pages/admin/roles.editor.vue Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> * fix: MkSelectに直接配列を指定している場合に正常に型が解決されるように --------- Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
This commit is contained in:
@@ -5,9 +5,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<template>
|
||||
<div class="_gaps">
|
||||
<MkSelect v-model="sortModeSelect">
|
||||
<MkSelect v-model="sortModeSelect" :items="sortModeSelectDef">
|
||||
<template #label>{{ i18n.ts.sort }}</template>
|
||||
<option v-for="x in sortOptions" :key="x.value" :value="x.value">{{ x.displayName }}</option>
|
||||
</MkSelect>
|
||||
<div v-if="!fetching">
|
||||
<MkPagination v-slot="{items}" :paginator="paginator">
|
||||
@@ -60,6 +59,7 @@ import { i18n } from '@/i18n.js';
|
||||
import bytes from '@/filters/bytes.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import { useMkSelect } from '@/composables/use-mkselect.js';
|
||||
import { getDriveFileMenu } from '@/utility/get-drive-file-menu.js';
|
||||
import { Paginator } from '@/utility/paginator.js';
|
||||
|
||||
@@ -69,15 +69,19 @@ const paginator = markRaw(new Paginator('drive/files', {
|
||||
computedParams: computed(() => ({ sort: sortMode.value })),
|
||||
}));
|
||||
|
||||
const sortOptions = [
|
||||
{ value: 'sizeDesc', displayName: i18n.ts._drivecleaner.orderBySizeDesc },
|
||||
{ value: 'createdAtAsc', displayName: i18n.ts._drivecleaner.orderByCreatedAtAsc },
|
||||
];
|
||||
|
||||
const capacity = ref<number>(0);
|
||||
const usage = ref<number>(0);
|
||||
const fetching = ref(true);
|
||||
const sortModeSelect = ref('sizeDesc');
|
||||
const {
|
||||
model: sortModeSelect,
|
||||
def: sortModeSelectDef,
|
||||
} = useMkSelect({
|
||||
items: [
|
||||
{ label: i18n.ts._drivecleaner.orderBySizeDesc, value: 'sizeDesc' },
|
||||
{ label: i18n.ts._drivecleaner.orderByCreatedAtAsc, value: 'createdAtAsc' },
|
||||
],
|
||||
initialValue: 'sizeDesc',
|
||||
});
|
||||
|
||||
fetchDriveInfo();
|
||||
|
||||
|
||||
@@ -36,20 +36,16 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<div class="_gaps_m">
|
||||
<SearchMarker :keywords="['main', 'palette']">
|
||||
<MkPreferenceContainer k="emojiPaletteForMain">
|
||||
<MkSelect v-model="emojiPaletteForMain">
|
||||
<MkSelect v-model="emojiPaletteForMain" :items="emojiPaletteForMainDef">
|
||||
<template #label><SearchLabel>{{ i18n.ts._emojiPalette.paletteForMain }}</SearchLabel></template>
|
||||
<option key="-" :value="null">({{ i18n.ts.auto }})</option>
|
||||
<option v-for="palette in prefer.r.emojiPalettes.value" :key="palette.id" :value="palette.id">{{ palette.name === '' ? '(' + i18n.ts.noName + ')' : palette.name }}</option>
|
||||
</MkSelect>
|
||||
</MkPreferenceContainer>
|
||||
</SearchMarker>
|
||||
|
||||
<SearchMarker :keywords="['reaction', 'palette']">
|
||||
<MkPreferenceContainer k="emojiPaletteForReaction">
|
||||
<MkSelect v-model="emojiPaletteForReaction">
|
||||
<MkSelect v-model="emojiPaletteForReaction" :items="emojiPaletteForReactionDef">
|
||||
<template #label><SearchLabel>{{ i18n.ts._emojiPalette.paletteForReaction }}</SearchLabel></template>
|
||||
<option key="-" :value="null">({{ i18n.ts.auto }})</option>
|
||||
<option v-for="palette in prefer.r.emojiPalettes.value" :key="palette.id" :value="palette.id">{{ palette.name === '' ? '(' + i18n.ts.noName + ')' : palette.name }}</option>
|
||||
</MkSelect>
|
||||
</MkPreferenceContainer>
|
||||
</SearchMarker>
|
||||
@@ -99,12 +95,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<SearchMarker :keywords="['emoji', 'picker', 'style']">
|
||||
<MkPreferenceContainer k="emojiPickerStyle">
|
||||
<MkSelect v-model="emojiPickerStyle">
|
||||
<MkSelect v-model="emojiPickerStyle" :items="[
|
||||
{ label: i18n.ts.auto, value: 'auto' },
|
||||
{ label: i18n.ts.popup, value: 'popup' },
|
||||
{ label: i18n.ts.drawer, value: 'drawer' },
|
||||
]">
|
||||
<template #label><SearchLabel>{{ i18n.ts.style }}</SearchLabel></template>
|
||||
<template #caption>{{ i18n.ts.needReloadToApply }}</template>
|
||||
<option value="auto">{{ i18n.ts.auto }}</option>
|
||||
<option value="popup">{{ i18n.ts.popup }}</option>
|
||||
<option value="drawer">{{ i18n.ts.drawer }}</option>
|
||||
</MkSelect>
|
||||
</MkPreferenceContainer>
|
||||
</SearchMarker>
|
||||
@@ -125,6 +122,7 @@ import MkRadios from '@/components/MkRadios.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import type { MkSelectItem } from '@/components/MkSelect.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
@@ -135,7 +133,21 @@ import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import { emojiPicker } from '@/utility/emoji-picker.js';
|
||||
|
||||
const emojiPaletteForReaction = prefer.model('emojiPaletteForReaction');
|
||||
const emojiPaletteForReactionDef = computed<MkSelectItem[]>(() => [
|
||||
{ label: `(${i18n.ts.auto})`, value: null },
|
||||
...prefer.s.emojiPalettes.map(palette => ({
|
||||
label: palette.name === '' ? `(${i18n.ts.noName})` : palette.name,
|
||||
value: palette.id,
|
||||
})),
|
||||
]);
|
||||
const emojiPaletteForMain = prefer.model('emojiPaletteForMain');
|
||||
const emojiPaletteForMainDef = computed<MkSelectItem[]>(() => [
|
||||
{ label: `(${i18n.ts.auto})`, value: null },
|
||||
...prefer.s.emojiPalettes.map(palette => ({
|
||||
label: palette.name === '' ? `(${i18n.ts.noName})` : palette.name,
|
||||
value: palette.id,
|
||||
})),
|
||||
]);
|
||||
const emojiPickerScale = prefer.model('emojiPickerScale');
|
||||
const emojiPickerWidth = prefer.model('emojiPickerWidth');
|
||||
const emojiPickerHeight = prefer.model('emojiPickerHeight');
|
||||
|
||||
@@ -86,9 +86,9 @@ async function addItem() {
|
||||
const { canceled, result: item } = await os.select({
|
||||
title: i18n.ts.addItem,
|
||||
items: [...menu.map(k => ({
|
||||
value: k, text: navbarItemDef[k].title,
|
||||
value: k, label: navbarItemDef[k].title,
|
||||
})), {
|
||||
value: '-', text: i18n.ts.divider,
|
||||
value: '-', label: i18n.ts.divider,
|
||||
}],
|
||||
});
|
||||
if (canceled || item == null) return;
|
||||
|
||||
@@ -5,13 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<template>
|
||||
<div class="_gaps_m">
|
||||
<MkSelect v-model="type">
|
||||
<option v-for="type in props.configurableTypes ?? notificationConfigTypes" :key="type" :value="type">{{ notificationConfigTypesI18nMap[type] }}</option>
|
||||
<MkSelect v-model="type" :items="typeDef">
|
||||
</MkSelect>
|
||||
|
||||
<MkSelect v-if="type === 'list'" v-model="userListId">
|
||||
<MkSelect v-if="type === 'list'" v-model="userListId" :items="userListIdDef">
|
||||
<template #label>{{ i18n.ts.userList }}</template>
|
||||
<option v-for="list in props.userLists" :key="list.id" :value="list.id">{{ list.name }}</option>
|
||||
</MkSelect>
|
||||
|
||||
<div class="_buttons">
|
||||
@@ -41,9 +39,10 @@ export type NotificationConfig = {
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { ref } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { useMkSelect } from '@/composables/use-mkselect.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -66,8 +65,26 @@ const notificationConfigTypesI18nMap: Record<typeof notificationConfigTypes[numb
|
||||
never: i18n.ts.none,
|
||||
};
|
||||
|
||||
const type = ref(props.value.type);
|
||||
const userListId = ref(props.value.type === 'list' ? props.value.userListId : null);
|
||||
const {
|
||||
model: type,
|
||||
def: typeDef,
|
||||
} = useMkSelect({
|
||||
items: computed(() => (props.configurableTypes ?? notificationConfigTypes).map((t: NotificationConfig['type']) => ({
|
||||
label: notificationConfigTypesI18nMap[t],
|
||||
value: t,
|
||||
}))),
|
||||
initialValue: props.value.type,
|
||||
});
|
||||
const {
|
||||
model: userListId,
|
||||
def: userListIdDef,
|
||||
} = useMkSelect({
|
||||
items: computed(() => props.userLists.map(list => ({
|
||||
label: list.name,
|
||||
value: list.id,
|
||||
}))),
|
||||
initialValue: props.value.type === 'list' ? props.value.userListId : null,
|
||||
});
|
||||
|
||||
function save() {
|
||||
emit('update', type.value === 'list' ? { type: type.value, userListId: userListId.value! } : { type: type.value });
|
||||
|
||||
@@ -18,9 +18,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<div class="_gaps_m">
|
||||
<SearchMarker :keywords="['language']">
|
||||
<MkSelect v-model="lang">
|
||||
<MkSelect v-model="lang" :items="langs.map(x => ({ label: x[1], value: x[0] }))">
|
||||
<template #label><SearchLabel>{{ i18n.ts.uiLanguage }}</SearchLabel></template>
|
||||
<option v-for="x in langs" :key="x[0]" :value="x[0]">{{ x[1] }}</option>
|
||||
<template #caption>
|
||||
<I18n :src="i18n.ts.i18nInfo" tag="span">
|
||||
<template #link>
|
||||
@@ -272,22 +271,31 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<SearchMarker :keywords="['ticker', 'information', 'label', 'instance', 'server', 'host', 'federation']">
|
||||
<MkPreferenceContainer k="instanceTicker">
|
||||
<MkSelect v-if="instance.federation !== 'none'" v-model="instanceTicker">
|
||||
<MkSelect
|
||||
v-if="instance.federation !== 'none'"
|
||||
v-model="instanceTicker"
|
||||
:items="[
|
||||
{ label: i18n.ts._instanceTicker.none, value: 'none' },
|
||||
{ label: i18n.ts._instanceTicker.remote, value: 'remote' },
|
||||
{ label: i18n.ts._instanceTicker.always, value: 'always' },
|
||||
]"
|
||||
>
|
||||
<template #label><SearchLabel>{{ i18n.ts.instanceTicker }}</SearchLabel></template>
|
||||
<option value="none">{{ i18n.ts._instanceTicker.none }}</option>
|
||||
<option value="remote">{{ i18n.ts._instanceTicker.remote }}</option>
|
||||
<option value="always">{{ i18n.ts._instanceTicker.always }}</option>
|
||||
</MkSelect>
|
||||
</MkPreferenceContainer>
|
||||
</SearchMarker>
|
||||
|
||||
<SearchMarker :keywords="['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'nsfw', 'sensitive', 'display', 'show', 'hide', 'visibility']">
|
||||
<MkPreferenceContainer k="nsfw">
|
||||
<MkSelect v-model="nsfw">
|
||||
<MkSelect
|
||||
v-model="nsfw"
|
||||
:items="[
|
||||
{ label: i18n.ts._displayOfSensitiveMedia.respect, value: 'respect' },
|
||||
{ label: i18n.ts._displayOfSensitiveMedia.ignore, value: 'ignore' },
|
||||
{ label: i18n.ts._displayOfSensitiveMedia.force, value: 'force' },
|
||||
]"
|
||||
>
|
||||
<template #label><SearchLabel>{{ i18n.ts.displayOfSensitiveMedia }}</SearchLabel></template>
|
||||
<option value="respect">{{ i18n.ts._displayOfSensitiveMedia.respect }}</option>
|
||||
<option value="ignore">{{ i18n.ts._displayOfSensitiveMedia.ignore }}</option>
|
||||
<option value="force">{{ i18n.ts._displayOfSensitiveMedia.force }}</option>
|
||||
</MkSelect>
|
||||
</MkPreferenceContainer>
|
||||
</SearchMarker>
|
||||
@@ -339,11 +347,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<div class="_gaps_m">
|
||||
<MkPreferenceContainer k="defaultNoteVisibility">
|
||||
<MkSelect v-model="defaultNoteVisibility">
|
||||
<option value="public">{{ i18n.ts._visibility.public }}</option>
|
||||
<option value="home">{{ i18n.ts._visibility.home }}</option>
|
||||
<option value="followers">{{ i18n.ts._visibility.followers }}</option>
|
||||
<option value="specified">{{ i18n.ts._visibility.specified }}</option>
|
||||
<MkSelect
|
||||
v-model="defaultNoteVisibility"
|
||||
:items="[
|
||||
{ label: i18n.ts._visibility.public, value: 'public' },
|
||||
{ label: i18n.ts._visibility.home, value: 'home' },
|
||||
{ label: i18n.ts._visibility.followers, value: 'followers' },
|
||||
{ label: i18n.ts._visibility.specified, value: 'specified' },
|
||||
]"
|
||||
>
|
||||
</MkSelect>
|
||||
</MkPreferenceContainer>
|
||||
|
||||
@@ -528,22 +540,30 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<SearchMarker :keywords="['menu', 'style', 'popup', 'drawer']">
|
||||
<MkPreferenceContainer k="menuStyle">
|
||||
<MkSelect v-model="menuStyle">
|
||||
<MkSelect
|
||||
v-model="menuStyle"
|
||||
:items="[
|
||||
{ label: i18n.ts.auto, value: 'auto' },
|
||||
{ label: i18n.ts.popup, value: 'popup' },
|
||||
{ label: i18n.ts.drawer, value: 'drawer' },
|
||||
]"
|
||||
>
|
||||
<template #label><SearchLabel>{{ i18n.ts.menuStyle }}</SearchLabel></template>
|
||||
<option value="auto">{{ i18n.ts.auto }}</option>
|
||||
<option value="popup">{{ i18n.ts.popup }}</option>
|
||||
<option value="drawer">{{ i18n.ts.drawer }}</option>
|
||||
</MkSelect>
|
||||
</MkPreferenceContainer>
|
||||
</SearchMarker>
|
||||
|
||||
<SearchMarker :keywords="['contextmenu', 'system', 'native']">
|
||||
<MkPreferenceContainer k="contextMenu">
|
||||
<MkSelect v-model="contextMenu">
|
||||
<MkSelect
|
||||
v-model="contextMenu"
|
||||
:items="[
|
||||
{ label: i18n.ts._contextMenu.app, value: 'app' },
|
||||
{ label: i18n.ts._contextMenu.appWithShift, value: 'appWithShift' },
|
||||
{ label: i18n.ts._contextMenu.native, value: 'native' },
|
||||
]"
|
||||
>
|
||||
<template #label><SearchLabel>{{ i18n.ts._contextMenu.title }}</SearchLabel></template>
|
||||
<option value="app">{{ i18n.ts._contextMenu.app }}</option>
|
||||
<option value="appWithShift">{{ i18n.ts._contextMenu.appWithShift }}</option>
|
||||
<option value="native">{{ i18n.ts._contextMenu.native }}</option>
|
||||
</MkSelect>
|
||||
</MkPreferenceContainer>
|
||||
</SearchMarker>
|
||||
@@ -719,11 +739,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<SearchMarker :keywords="['server', 'disconnect', 'reconnect', 'reload', 'streaming']">
|
||||
<MkPreferenceContainer k="serverDisconnectedBehavior">
|
||||
<MkSelect v-model="serverDisconnectedBehavior">
|
||||
<MkSelect
|
||||
v-model="serverDisconnectedBehavior"
|
||||
:items="[
|
||||
{ label: i18n.ts._serverDisconnectedBehavior.reload, value: 'reload' },
|
||||
{ label: i18n.ts._serverDisconnectedBehavior.dialog, value: 'dialog' },
|
||||
{ label: i18n.ts._serverDisconnectedBehavior.quiet, value: 'quiet' },
|
||||
]"
|
||||
>
|
||||
<template #label><SearchLabel>{{ i18n.ts.whenServerDisconnected }}</SearchLabel></template>
|
||||
<option value="reload">{{ i18n.ts._serverDisconnectedBehavior.reload }}</option>
|
||||
<option value="dialog">{{ i18n.ts._serverDisconnectedBehavior.dialog }}</option>
|
||||
<option value="quiet">{{ i18n.ts._serverDisconnectedBehavior.quiet }}</option>
|
||||
</MkSelect>
|
||||
</MkPreferenceContainer>
|
||||
</SearchMarker>
|
||||
@@ -984,16 +1008,15 @@ function removeEmojiIndex(lang: string) {
|
||||
|
||||
async function setPinnedList() {
|
||||
const lists = await misskeyApi('users/lists/list');
|
||||
const { canceled, result: list } = await os.select({
|
||||
const { canceled, result: listId } = await os.select({
|
||||
title: i18n.ts.selectList,
|
||||
items: lists.map(x => ({
|
||||
value: x, text: x.name,
|
||||
value: x.id, label: x.name,
|
||||
})),
|
||||
});
|
||||
if (canceled) return;
|
||||
if (list == null) return;
|
||||
if (canceled || listId == null) return;
|
||||
|
||||
prefer.commit('pinnedUserLists', [list]);
|
||||
prefer.commit('pinnedUserLists', [lists.find((x) => x.id === listId)!]);
|
||||
}
|
||||
|
||||
function removePinnedList() {
|
||||
|
||||
@@ -33,20 +33,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</SearchMarker>
|
||||
|
||||
<SearchMarker :keywords="['following', 'visibility']">
|
||||
<MkSelect v-model="followingVisibility" @update:modelValue="save()">
|
||||
<MkSelect v-model="followingVisibility" :items="followingVisibilityDef" @update:modelValue="save()">
|
||||
<template #label><SearchLabel>{{ i18n.ts.followingVisibility }}</SearchLabel></template>
|
||||
<option value="public">{{ i18n.ts._ffVisibility.public }}</option>
|
||||
<option value="followers">{{ i18n.ts._ffVisibility.followers }}</option>
|
||||
<option value="private">{{ i18n.ts._ffVisibility.private }}</option>
|
||||
</MkSelect>
|
||||
</SearchMarker>
|
||||
|
||||
<SearchMarker :keywords="['follower', 'visibility']">
|
||||
<MkSelect v-model="followersVisibility" @update:modelValue="save()">
|
||||
<MkSelect v-model="followersVisibility" :items="followersVisibilityDef" @update:modelValue="save()">
|
||||
<template #label><SearchLabel>{{ i18n.ts.followersVisibility }}</SearchLabel></template>
|
||||
<option value="public">{{ i18n.ts._ffVisibility.public }}</option>
|
||||
<option value="followers">{{ i18n.ts._ffVisibility.followers }}</option>
|
||||
<option value="private">{{ i18n.ts._ffVisibility.private }}</option>
|
||||
</MkSelect>
|
||||
</SearchMarker>
|
||||
|
||||
@@ -85,13 +79,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<div class="_gaps_m">
|
||||
<MkInfo v-if="$i.policies.chatAvailability === 'unavailable'">{{ i18n.ts._chat.chatNotAvailableForThisAccountOrServer }}</MkInfo>
|
||||
<SearchMarker :keywords="['chat']">
|
||||
<MkSelect v-model="chatScope" @update:modelValue="save()">
|
||||
<MkSelect v-model="chatScope" :items="chatScopeDef" @update:modelValue="save()">
|
||||
<template #label><SearchLabel>{{ i18n.ts._chat.chatAllowedUsers }}</SearchLabel></template>
|
||||
<option value="everyone">{{ i18n.ts._chat._chatAllowedUsers.everyone }}</option>
|
||||
<option value="followers">{{ i18n.ts._chat._chatAllowedUsers.followers }}</option>
|
||||
<option value="following">{{ i18n.ts._chat._chatAllowedUsers.following }}</option>
|
||||
<option value="mutual">{{ i18n.ts._chat._chatAllowedUsers.mutual }}</option>
|
||||
<option value="none">{{ i18n.ts._chat._chatAllowedUsers.none }}</option>
|
||||
<template #caption>{{ i18n.ts._chat.chatAllowedUsers_note }}</template>
|
||||
</MkSelect>
|
||||
</SearchMarker>
|
||||
@@ -119,15 +108,24 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<template #label><SearchLabel>{{ i18n.ts._accountSettings.makeNotesFollowersOnlyBefore }}</SearchLabel></template>
|
||||
|
||||
<div class="_gaps_s">
|
||||
<MkSelect v-model="makeNotesFollowersOnlyBefore_type">
|
||||
<option :value="null">{{ i18n.ts.none }}</option>
|
||||
<option value="relative">{{ i18n.ts._accountSettings.notesHavePassedSpecifiedPeriod }}</option>
|
||||
<option value="absolute">{{ i18n.ts._accountSettings.notesOlderThanSpecifiedDateAndTime }}</option>
|
||||
<MkSelect
|
||||
v-model="makeNotesFollowersOnlyBefore_type"
|
||||
:items="[
|
||||
{ label: i18n.ts.none, value: null },
|
||||
{ label: i18n.ts._accountSettings.notesHavePassedSpecifiedPeriod, value: 'relative' },
|
||||
{ label: i18n.ts._accountSettings.notesOlderThanSpecifiedDateAndTime, value: 'absolute' },
|
||||
]"
|
||||
>
|
||||
</MkSelect>
|
||||
|
||||
<MkSelect v-if="makeNotesFollowersOnlyBefore_type === 'relative'" v-model="makeNotesFollowersOnlyBefore_selection">
|
||||
<option v-for="preset in makeNotesFollowersOnlyBefore_presets" :value="preset.value">{{ preset.label }}</option>
|
||||
<option value="custom">{{ i18n.ts.custom }}</option>
|
||||
<MkSelect
|
||||
v-if="makeNotesFollowersOnlyBefore_type === 'relative'"
|
||||
v-model="makeNotesFollowersOnlyBefore_selection"
|
||||
:items="[
|
||||
...makeNotesFollowersOnlyBefore_presets,
|
||||
{ label: i18n.ts.custom, value: 'custom' },
|
||||
]"
|
||||
>
|
||||
</MkSelect>
|
||||
|
||||
<MkInput
|
||||
@@ -162,22 +160,22 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<div class="_gaps_s">
|
||||
<MkSelect
|
||||
v-model="makeNotesHiddenBefore_type"
|
||||
:items="[{
|
||||
value: null,
|
||||
label: i18n.ts.none
|
||||
}, {
|
||||
value: 'relative',
|
||||
label: i18n.ts._accountSettings.notesHavePassedSpecifiedPeriod
|
||||
}, {
|
||||
value: 'absolute',
|
||||
label: i18n.ts._accountSettings.notesOlderThanSpecifiedDateAndTime
|
||||
}]"
|
||||
:items="[
|
||||
{ label: i18n.ts.none, value: null },
|
||||
{ label: i18n.ts._accountSettings.notesHavePassedSpecifiedPeriod, value: 'relative' },
|
||||
{ label: i18n.ts._accountSettings.notesOlderThanSpecifiedDateAndTime, value: 'absolute' },
|
||||
]"
|
||||
>
|
||||
</MkSelect>
|
||||
|
||||
<MkSelect v-if="makeNotesHiddenBefore_type === 'relative'" v-model="makeNotesHiddenBefore_selection">
|
||||
<option v-for="preset in makeNotesHiddenBefore_presets" :value="preset.value">{{ preset.label }}</option>
|
||||
<option value="custom">{{ i18n.ts.custom }}</option>
|
||||
<MkSelect
|
||||
v-if="makeNotesHiddenBefore_type === 'relative'"
|
||||
v-model="makeNotesHiddenBefore_selection"
|
||||
:items="[
|
||||
...makeNotesHiddenBefore_presets,
|
||||
{ label: i18n.ts.custom, value: 'custom' },
|
||||
]"
|
||||
>
|
||||
</MkSelect>
|
||||
|
||||
<MkInput
|
||||
@@ -217,6 +215,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import type { MkSelectItem } from '@/components/MkSelect.vue';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
@@ -225,6 +224,7 @@ import { ensureSignin } from '@/i.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import FormSlot from '@/components/form/slot.vue';
|
||||
import { formatDateTimeString } from '@/utility/format-time-string.js';
|
||||
import { useMkSelect } from '@/composables/use-mkselect.js';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import * as os from '@/os.js';
|
||||
import MkDisableSection from '@/components/MkDisableSection.vue';
|
||||
@@ -243,9 +243,41 @@ const makeNotesFollowersOnlyBefore = ref($i.makeNotesFollowersOnlyBefore ?? null
|
||||
const makeNotesHiddenBefore = ref($i.makeNotesHiddenBefore ?? null);
|
||||
const hideOnlineStatus = ref($i.hideOnlineStatus);
|
||||
const publicReactions = ref($i.publicReactions);
|
||||
const followingVisibility = ref($i.followingVisibility);
|
||||
const followersVisibility = ref($i.followersVisibility);
|
||||
const chatScope = ref($i.chatScope);
|
||||
const {
|
||||
model: followingVisibility,
|
||||
def: followingVisibilityDef,
|
||||
} = useMkSelect({
|
||||
items: [
|
||||
{ label: i18n.ts.public, value: 'public' },
|
||||
{ label: i18n.ts.followers, value: 'followers' },
|
||||
{ label: i18n.ts.private, value: 'private' },
|
||||
],
|
||||
initialValue: $i.followingVisibility,
|
||||
});
|
||||
const {
|
||||
model: followersVisibility,
|
||||
def: followersVisibilityDef,
|
||||
} = useMkSelect({
|
||||
items: [
|
||||
{ label: i18n.ts.public, value: 'public' },
|
||||
{ label: i18n.ts.followers, value: 'followers' },
|
||||
{ label: i18n.ts.private, value: 'private' },
|
||||
],
|
||||
initialValue: $i.followersVisibility,
|
||||
});
|
||||
const {
|
||||
model: chatScope,
|
||||
def: chatScopeDef,
|
||||
} = useMkSelect({
|
||||
items: [
|
||||
{ label: i18n.ts._chat._chatAllowedUsers.everyone, value: 'everyone' },
|
||||
{ label: i18n.ts._chat._chatAllowedUsers.followers, value: 'followers' },
|
||||
{ label: i18n.ts._chat._chatAllowedUsers.following, value: 'following' },
|
||||
{ label: i18n.ts._chat._chatAllowedUsers.mutual, value: 'mutual' },
|
||||
{ label: i18n.ts._chat._chatAllowedUsers.none, value: 'none' },
|
||||
],
|
||||
initialValue: $i.chatScope,
|
||||
});
|
||||
|
||||
const makeNotesFollowersOnlyBefore_type = computed({
|
||||
get: () => {
|
||||
@@ -276,7 +308,7 @@ const makeNotesFollowersOnlyBefore_presets = [
|
||||
{ label: i18n.ts.oneMonth, value: -2592000 },
|
||||
{ label: i18n.ts.threeMonths, value: -7776000 },
|
||||
{ label: i18n.ts.oneYear, value: -31104000 },
|
||||
];
|
||||
] satisfies MkSelectItem[];
|
||||
|
||||
const makeNotesFollowersOnlyBefore_isCustomMode = ref(
|
||||
makeNotesFollowersOnlyBefore.value != null &&
|
||||
@@ -328,7 +360,7 @@ const makeNotesHiddenBefore_presets = [
|
||||
{ label: i18n.ts.oneMonth, value: -2592000 },
|
||||
{ label: i18n.ts.threeMonths, value: -7776000 },
|
||||
{ label: i18n.ts.oneYear, value: -31104000 },
|
||||
];
|
||||
] satisfies MkSelectItem[];
|
||||
|
||||
const makeNotesHiddenBefore_isCustomMode = ref(
|
||||
makeNotesHiddenBefore.value != null &&
|
||||
|
||||
@@ -53,9 +53,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</SearchMarker>
|
||||
|
||||
<SearchMarker :keywords="['language', 'locale']">
|
||||
<MkSelect v-model="profile.lang">
|
||||
<MkSelect v-model="profile.lang" :items="Object.entries(langmap).map(([code, def]) => ({ label: def.nativeName, value: code }))">
|
||||
<template #label><SearchLabel>{{ i18n.ts.language }}</SearchLabel></template>
|
||||
<option v-for="x in Object.keys(langmap)" :key="x" :value="x">{{ langmap[x].nativeName }}</option>
|
||||
</MkSelect>
|
||||
</SearchMarker>
|
||||
|
||||
@@ -117,13 +116,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</SearchMarker>
|
||||
|
||||
<SearchMarker :keywords="['reaction']">
|
||||
<MkSelect v-model="reactionAcceptance">
|
||||
<MkSelect
|
||||
v-model="reactionAcceptance"
|
||||
:items="[
|
||||
{ label: i18n.ts.all, value: null },
|
||||
{ label: i18n.ts.likeOnlyForRemote, value: 'likeOnlyForRemote' },
|
||||
{ label: i18n.ts.nonSensitiveOnly, value: 'nonSensitiveOnly' },
|
||||
{ label: i18n.ts.nonSensitiveOnlyForLocalLikeOnlyForRemote, value: 'nonSensitiveOnlyForLocalLikeOnlyForRemote' },
|
||||
{ label: i18n.ts.likeOnly, value: 'likeOnly' },
|
||||
]"
|
||||
>
|
||||
<template #label><SearchLabel>{{ i18n.ts.reactionAcceptance }}</SearchLabel></template>
|
||||
<option :value="null">{{ i18n.ts.all }}</option>
|
||||
<option value="likeOnlyForRemote">{{ i18n.ts.likeOnlyForRemote }}</option>
|
||||
<option value="nonSensitiveOnly">{{ i18n.ts.nonSensitiveOnly }}</option>
|
||||
<option value="nonSensitiveOnlyForLocalLikeOnlyForRemote">{{ i18n.ts.nonSensitiveOnlyForLocalLikeOnlyForRemote }}</option>
|
||||
<option value="likeOnly">{{ i18n.ts.likeOnly }}</option>
|
||||
</MkSelect>
|
||||
</SearchMarker>
|
||||
|
||||
|
||||
@@ -5,9 +5,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<template>
|
||||
<div class="_gaps_m">
|
||||
<MkSelect v-model="type">
|
||||
<MkSelect v-model="type" :items="typeDef">
|
||||
<template #label>{{ i18n.ts.sound }}</template>
|
||||
<option v-for="x in soundsTypes" :key="x ?? 'null'" :value="x">{{ getSoundTypeName(x) }}</option>
|
||||
</MkSelect>
|
||||
<div v-if="type === '_driveFile_' && driveFileError === true" :class="$style.fileSelectorRoot">
|
||||
<MkButton :class="$style.fileSelectorButton" inline rounded primary @click="selectSound">{{ i18n.ts.selectFile }}</MkButton>
|
||||
@@ -38,6 +37,7 @@ import MkButton from '@/components/MkButton.vue';
|
||||
import MkRange from '@/components/MkRange.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import * as os from '@/os.js';
|
||||
import { useMkSelect } from '@/composables/use-mkselect.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { playMisskeySfxFile, soundsTypes, getSoundDuration } from '@/utility/sound.js';
|
||||
import { selectFile } from '@/utility/drive.js';
|
||||
@@ -51,7 +51,16 @@ const emit = defineEmits<{
|
||||
(ev: 'update', result: { type: SoundType; fileId?: string; fileUrl?: string; volume: number; }): void;
|
||||
}>();
|
||||
|
||||
const type = ref<SoundType>(props.def.type);
|
||||
const {
|
||||
model: type,
|
||||
def: typeDef,
|
||||
} = useMkSelect({
|
||||
items: soundsTypes.map((x) => ({
|
||||
label: getSoundTypeName(x),
|
||||
value: x,
|
||||
})),
|
||||
initialValue: props.def.type,
|
||||
});
|
||||
const fileId = ref('fileId' in props.def ? props.def.fileId : undefined);
|
||||
const fileUrl = ref('fileUrl' in props.def ? props.def.fileUrl : undefined);
|
||||
const fileName = ref<string>('');
|
||||
|
||||
@@ -5,11 +5,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<template>
|
||||
<div class="_gaps_m">
|
||||
<MkSelect v-model="statusbar.type" placeholder="Please select">
|
||||
<MkSelect v-model="statusbar.type" :items="statusbarTypeDef">
|
||||
<template #label>{{ i18n.ts.type }}</template>
|
||||
<option value="rss">RSS</option>
|
||||
<option v-if="instance.federation !== 'none'" value="federation">Federation</option>
|
||||
<option value="userList">User list timeline</option>
|
||||
</MkSelect>
|
||||
|
||||
<MkInput v-model="statusbar.name" manualSave>
|
||||
@@ -63,9 +60,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</MkSwitch>
|
||||
</template>
|
||||
<template v-else-if="statusbar.type === 'userList' && userLists != null">
|
||||
<MkSelect v-model="statusbar.props.userListId">
|
||||
<MkSelect v-model="statusbar.props.userListId" :items="userListsDef">
|
||||
<template #label>{{ i18n.ts.userList }}</template>
|
||||
<option v-for="list in userLists" :value="list.id">{{ list.name }}</option>
|
||||
</MkSelect>
|
||||
<MkInput v-model="statusbar.props.refreshIntervalSec" manualSave type="number">
|
||||
<template #label>{{ i18n.ts.refreshInterval }}</template>
|
||||
@@ -86,7 +82,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, watch } from 'vue';
|
||||
import { reactive, computed, watch } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
@@ -98,13 +94,32 @@ import { i18n } from '@/i18n.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { deepClone } from '@/utility/clone.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import type { MkSelectItem } from '@/components/MkSelect.vue';
|
||||
import type { StatusbarStore } from '@/preferences/def.js';
|
||||
|
||||
const props = defineProps<{
|
||||
_id: string;
|
||||
userLists: Misskey.entities.UserList[] | null;
|
||||
}>();
|
||||
|
||||
const statusbar = reactive(deepClone(prefer.s.statusbars.find(x => x.id === props._id))!);
|
||||
const statusbar = reactive<StatusbarStore>(deepClone(prefer.s.statusbars.find(x => x.id === props._id)!));
|
||||
|
||||
const statusbarTypeDef = computed(() => {
|
||||
const items = [
|
||||
{ label: 'RSS', value: 'rss' },
|
||||
] satisfies MkSelectItem[];
|
||||
if (instance.federation !== 'none') {
|
||||
items.push({ label: 'Federation', value: 'federation' });
|
||||
}
|
||||
if (props.userLists != null) {
|
||||
items.push({ label: i18n.ts.userList, value: 'userList' });
|
||||
}
|
||||
return items;
|
||||
});
|
||||
|
||||
const userListsDef = computed(() => {
|
||||
return (props.userLists ?? []).map(x => ({ label: x.name, value: x.id })) satisfies MkSelectItem[];
|
||||
});
|
||||
|
||||
watch(() => statusbar.type, () => {
|
||||
if (statusbar.type === 'rss') {
|
||||
|
||||
@@ -5,16 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<template>
|
||||
<div class="_gaps_m">
|
||||
<MkSelect v-model="selectedThemeId">
|
||||
<MkSelect v-model="selectedThemeId" :items="selectedThemeIdDef">
|
||||
<template #label>{{ i18n.ts.theme }}</template>
|
||||
<optgroup :label="i18n.ts._theme.installedThemes">
|
||||
<option v-for="x in installedThemes" :key="x.id" :value="x.id">{{ x.name }}</option>
|
||||
</optgroup>
|
||||
<optgroup :label="i18n.ts._theme.builtinThemes">
|
||||
<option v-for="x in builtinThemes" :key="x.id" :value="x.id">{{ x.name }}</option>
|
||||
</optgroup>
|
||||
</MkSelect>
|
||||
<template v-if="selectedTheme">
|
||||
<template v-if="selectedTheme != null">
|
||||
<MkInput readonly :modelValue="selectedTheme.author">
|
||||
<template #label>{{ i18n.ts.author }}</template>
|
||||
</MkInput>
|
||||
@@ -43,10 +37,26 @@ import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { useMkSelect } from '@/composables/use-mkselect.js';
|
||||
import type { MkSelectItem } from '@/components/MkSelect.vue';
|
||||
|
||||
const installedThemes = getThemesRef();
|
||||
const builtinThemes = getBuiltinThemesRef();
|
||||
const selectedThemeId = ref<string | null>(null);
|
||||
const {
|
||||
model: selectedThemeId,
|
||||
def: selectedThemeIdDef,
|
||||
} = useMkSelect({
|
||||
items: computed<MkSelectItem<string | null>[]>(() => [{
|
||||
type: 'group',
|
||||
label: i18n.ts._theme.installedThemes,
|
||||
items: installedThemes.value.map(x => ({ label: x.name, value: x.id })),
|
||||
}, {
|
||||
type: 'group',
|
||||
label: i18n.ts._theme.builtinThemes,
|
||||
items: builtinThemes.value.map(x => ({ label: x.name, value: x.id })),
|
||||
}]),
|
||||
initialValue: null,
|
||||
});
|
||||
|
||||
const themes = computed(() => [...installedThemes.value, ...builtinThemes.value]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user