Merge remote-tracking branch 'misskey/master' into feature/misskey-2024.07
This commit is contained in:
commit
cfa9b852df
585 changed files with 23423 additions and 9623 deletions
|
|
@ -108,9 +108,11 @@ async function registerTOTP(): Promise<void> {
|
|||
token: auth.result.token,
|
||||
});
|
||||
|
||||
os.popup(defineAsyncComponent(() => import('./2fa.qrdialog.vue')), {
|
||||
const { dispose } = os.popup(defineAsyncComponent(() => import('./2fa.qrdialog.vue')), {
|
||||
twoFactorData,
|
||||
}, {}, 'closed');
|
||||
}, {
|
||||
closed: () => dispose(),
|
||||
});
|
||||
}
|
||||
|
||||
async function unregisterTOTP(): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -74,22 +74,24 @@ async function removeAccount(account) {
|
|||
}
|
||||
|
||||
function addExistingAccount() {
|
||||
os.popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {}, {
|
||||
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {}, {
|
||||
done: async res => {
|
||||
await addAccounts(res.id, res.i);
|
||||
os.success();
|
||||
init();
|
||||
},
|
||||
}, 'closed');
|
||||
closed: () => dispose(),
|
||||
});
|
||||
}
|
||||
|
||||
function createAccount() {
|
||||
os.popup(defineAsyncComponent(() => import('@/components/MkSignupDialog.vue')), {}, {
|
||||
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkSignupDialog.vue')), {}, {
|
||||
done: async res => {
|
||||
await addAccounts(res.id, res.i);
|
||||
switchAccountWithToken(res.i);
|
||||
},
|
||||
}, 'closed');
|
||||
closed: () => dispose(),
|
||||
});
|
||||
}
|
||||
|
||||
async function switchAccount(account: any) {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
|||
const isDesktop = ref(window.innerWidth >= 1100);
|
||||
|
||||
function generateToken() {
|
||||
os.popup(defineAsyncComponent(() => import('@/components/MkTokenGenerateWindow.vue')), {}, {
|
||||
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTokenGenerateWindow.vue')), {}, {
|
||||
done: async result => {
|
||||
const { name, permissions } = result;
|
||||
const { token } = await misskeyApi('miauth/gen-token', {
|
||||
|
|
@ -38,7 +38,8 @@ function generateToken() {
|
|||
text: token,
|
||||
});
|
||||
},
|
||||
}, 'closed');
|
||||
closed: () => dispose(),
|
||||
});
|
||||
}
|
||||
|
||||
const headerActions = computed(() => []);
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ misskeyApi('get-avatar-decorations').then(_avatarDecorations => {
|
|||
});
|
||||
|
||||
function openDecoration(avatarDecoration, index?: number) {
|
||||
os.popup(defineAsyncComponent(() => import('./avatar-decoration.dialog.vue')), {
|
||||
const { dispose } = os.popup(defineAsyncComponent(() => import('./avatar-decoration.dialog.vue')), {
|
||||
decoration: avatarDecoration,
|
||||
usingIndex: index,
|
||||
}, {
|
||||
|
|
@ -108,7 +108,8 @@ function openDecoration(avatarDecoration, index?: number) {
|
|||
});
|
||||
$i.avatarDecorations = update;
|
||||
},
|
||||
}, 'closed');
|
||||
closed: () => dispose(),
|
||||
});
|
||||
}
|
||||
|
||||
function detachAllDecorations() {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { computed, ref, watch, type StyleValue } from 'vue';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||
|
|
@ -102,10 +102,10 @@ function fetchDriveInfo(): void {
|
|||
});
|
||||
}
|
||||
|
||||
function genUsageBar(fsize: number): object {
|
||||
function genUsageBar(fsize: number): StyleValue {
|
||||
return {
|
||||
width: `${fsize / usage.value * 100}%`,
|
||||
background: tinycolor({ h: 180 - (fsize / usage.value * 180), s: 0.7, l: 0.5 }),
|
||||
background: tinycolor({ h: 180 - (fsize / usage.value * 180), s: 0.7, l: 0.5 }).toHslString(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ const meterStyle = computed(() => {
|
|||
h: 180 - (usage.value / capacity.value * 180),
|
||||
s: 0.7,
|
||||
l: 0.5,
|
||||
}),
|
||||
}).toHslString(),
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -234,6 +234,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkSwitch v-model="disableStreamingTimeline">{{ i18n.ts.disableStreamingTimeline }}</MkSwitch>
|
||||
<MkSwitch v-model="enableHorizontalSwipe">{{ i18n.ts.enableHorizontalSwipe }}</MkSwitch>
|
||||
<MkSwitch v-model="alwaysConfirmFollow">{{ i18n.ts.alwaysConfirmFollow }}</MkSwitch>
|
||||
<MkSwitch v-model="confirmWhenRevealingSensitiveMedia">{{ i18n.ts.confirmWhenRevealingSensitiveMedia }}</MkSwitch>
|
||||
</div>
|
||||
<MkSelect v-model="serverDisconnectedBehavior">
|
||||
<template #label>{{ i18n.ts.whenServerDisconnected }}</template>
|
||||
|
|
@ -241,6 +242,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<option value="quiet">{{ i18n.ts._serverDisconnectedBehavior.quiet }}</option>
|
||||
<option value="disabled">{{ i18n.ts._serverDisconnectedBehavior.disabled }}</option>
|
||||
</MkSelect>
|
||||
<MkSelect v-model="contextMenu">
|
||||
<template #label>{{ i18n.ts._contextMenu.title }}</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>
|
||||
<MkRange v-model="numberOfPageCache" :min="1" :max="10" :step="1" easing>
|
||||
<template #label>{{ i18n.ts.numberOfPageCache }}</template>
|
||||
<template #caption>{{ i18n.ts.numberOfPageCacheDescription }}</template>
|
||||
|
|
@ -426,6 +433,8 @@ const visibilityOnBoost = computed(defaultStore.makeGetterSetter('visibilityOnBo
|
|||
const enableHorizontalSwipe = computed(defaultStore.makeGetterSetter('enableHorizontalSwipe'));
|
||||
const useNativeUIForVideoAudioPlayer = computed(defaultStore.makeGetterSetter('useNativeUIForVideoAudioPlayer'));
|
||||
const alwaysConfirmFollow = computed(defaultStore.makeGetterSetter('alwaysConfirmFollow'));
|
||||
const confirmWhenRevealingSensitiveMedia = computed(defaultStore.makeGetterSetter('confirmWhenRevealingSensitiveMedia'));
|
||||
const contextMenu = computed(defaultStore.makeGetterSetter('contextMenu'));
|
||||
|
||||
watch(lang, () => {
|
||||
miLocalStorage.setItem('lang', lang.value as string);
|
||||
|
|
@ -485,6 +494,8 @@ watch([
|
|||
showVisibilitySelectorOnBoost,
|
||||
visibilityOnBoost,
|
||||
alwaysConfirmFollow,
|
||||
confirmWhenRevealingSensitiveMedia,
|
||||
contextMenu,
|
||||
], async () => {
|
||||
await reloadAsk();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ import MkCode from '@/components/MkCode.vue';
|
|||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||
import * as os from '@/os.js';
|
||||
import copyToClipboard from '@/scripts/copy-to-clipboard.js';
|
||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||
import { ColdDeviceStorage } from '@/store.js';
|
||||
import { unisonReload } from '@/scripts/unison-reload.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
|
|
|||
|
|
@ -118,8 +118,6 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
|
|||
'sound_note',
|
||||
'sound_noteMy',
|
||||
'sound_notification',
|
||||
'sound_antenna',
|
||||
'sound_channel',
|
||||
];
|
||||
const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
|
||||
'lightTheme',
|
||||
|
|
|
|||
|
|
@ -481,6 +481,7 @@ definePageMetadata(() => ({
|
|||
&:hover, &:focus {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
&:active {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<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_'" :class="$style.fileSelectorRoot">
|
||||
<div v-if="type === '_driveFile_' && driveFileError === true" :class="$style.fileSelectorRoot">
|
||||
<MkButton :class="$style.fileSelectorButton" inline rounded primary @click="selectSound">{{ i18n.ts.selectFile }}</MkButton>
|
||||
<div :class="$style.fileErrorRoot">
|
||||
<MkCondensedLine>{{ i18n.ts._soundSettings.driveFileError }}</MkCondensedLine>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="type === '_driveFile_'" :class="$style.fileSelectorRoot">
|
||||
<MkButton :class="$style.fileSelectorButton" inline rounded primary @click="selectSound">{{ i18n.ts.selectFile }}</MkButton>
|
||||
<div :class="['_nowrap', !fileUrl && $style.fileNotSelected]">{{ friendlyFileName }}</div>
|
||||
</div>
|
||||
|
|
@ -19,13 +25,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<div class="_buttons">
|
||||
<MkButton inline @click="listen"><i class="ti ti-player-play"></i> {{ i18n.ts.listen }}</MkButton>
|
||||
<MkButton inline primary @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
|
||||
<MkButton inline primary :disabled="!hasChanged || driveFileError" @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import type { SoundType } from '@/scripts/sound.js';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
|
@ -51,13 +57,18 @@ const type = ref<SoundType>(props.type);
|
|||
const fileId = ref(props.fileId);
|
||||
const fileUrl = ref(props.fileUrl);
|
||||
const fileName = ref<string>('');
|
||||
const driveFileError = ref(false);
|
||||
const hasChanged = ref(false);
|
||||
const volume = ref(props.volume);
|
||||
|
||||
if (type.value === '_driveFile_' && fileId.value) {
|
||||
const apiRes = await misskeyApi('drive/files/show', {
|
||||
await misskeyApi('drive/files/show', {
|
||||
fileId: fileId.value,
|
||||
}).then((res) => {
|
||||
fileName.value = res.name;
|
||||
}).catch((res) => {
|
||||
driveFileError.value = true;
|
||||
});
|
||||
fileName.value = apiRes.name;
|
||||
}
|
||||
|
||||
function getSoundTypeName(f: SoundType): string {
|
||||
|
|
@ -107,9 +118,21 @@ function selectSound(ev) {
|
|||
fileUrl.value = file.url;
|
||||
fileName.value = file.name;
|
||||
fileId.value = file.id;
|
||||
driveFileError.value = false;
|
||||
hasChanged.value = true;
|
||||
});
|
||||
}
|
||||
|
||||
watch([type, volume], ([typeTo, volumeTo], [typeFrom, volumeFrom]) => {
|
||||
if (typeFrom !== typeTo && typeTo !== '_driveFile_') {
|
||||
fileUrl.value = undefined;
|
||||
fileName.value = '';
|
||||
fileId.value = undefined;
|
||||
driveFileError.value = false;
|
||||
}
|
||||
hasChanged.value = true;
|
||||
});
|
||||
|
||||
function listen() {
|
||||
if (type.value === '_driveFile_' && (!fileUrl.value || !fileId.value)) {
|
||||
os.alert({
|
||||
|
|
@ -131,6 +154,10 @@ function listen() {
|
|||
}
|
||||
|
||||
function save() {
|
||||
if (hasChanged.value === false || driveFileError.value === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type.value === '_driveFile_' && !fileUrl.value) {
|
||||
os.alert({
|
||||
type: 'warning',
|
||||
|
|
@ -163,6 +190,13 @@ function save() {
|
|||
gap: 8px;
|
||||
}
|
||||
|
||||
.fileErrorRoot {
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
font-weight: 700;
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
.fileSelectorButton {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkFolder v-for="type in operationTypes" :key="type">
|
||||
<template #label>{{ i18n.ts._sfx[type] }}</template>
|
||||
<template #suffix>{{ getSoundTypeName(sounds[type].type) }}</template>
|
||||
|
||||
<XSound :type="sounds[type].type" :volume="sounds[type].volume" :fileId="sounds[type].fileId" :fileUrl="sounds[type].fileUrl" @update="(res) => updated(type, res)"/>
|
||||
<Suspense>
|
||||
<template #default>
|
||||
<XSound :type="sounds[type].type" :volume="sounds[type].volume" :fileId="sounds[type].fileId" :fileUrl="sounds[type].fileUrl" @update="(res) => updated(type, res)"/>
|
||||
</template>
|
||||
<template #fallback>
|
||||
<MkLoading/>
|
||||
</template>
|
||||
</Suspense>
|
||||
</MkFolder>
|
||||
</div>
|
||||
</FormSection>
|
||||
|
|
@ -54,8 +60,6 @@ const sounds = ref<Record<OperationType, Ref<SoundStore>>>({
|
|||
note: defaultStore.reactiveState.sound_note,
|
||||
noteMy: defaultStore.reactiveState.sound_noteMy,
|
||||
notification: defaultStore.reactiveState.sound_notification,
|
||||
antenna: defaultStore.reactiveState.sound_antenna,
|
||||
channel: defaultStore.reactiveState.sound_channel,
|
||||
reaction: defaultStore.reactiveState.sound_reaction,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkSwitch v-model="statusbar.props.shuffle">
|
||||
<template #label>{{ i18n.ts.shuffle }}</template>
|
||||
</MkSwitch>
|
||||
<MkInput v-model="statusbar.props.refreshIntervalSec" manualSave type="number">
|
||||
<MkInput v-model="statusbar.props.refreshIntervalSec" manualSave type="number" min="1">
|
||||
<template #label>{{ i18n.ts.refreshInterval }}</template>
|
||||
</MkInput>
|
||||
<MkRange v-model="statusbar.props.marqueeDuration" :min="5" :max="150" :step="1">
|
||||
|
|
@ -48,7 +48,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkSwitch>
|
||||
</template>
|
||||
<template v-else-if="statusbar.type === 'federation'">
|
||||
<MkInput v-model="statusbar.props.refreshIntervalSec" manualSave type="number">
|
||||
<MkInput v-model="statusbar.props.refreshIntervalSec" manualSave type="number" min="1">
|
||||
<template #label>{{ i18n.ts.refreshInterval }}</template>
|
||||
</MkInput>
|
||||
<MkRange v-model="statusbar.props.marqueeDuration" :min="5" :max="150" :step="1">
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ import MkSelect from '@/components/MkSelect.vue';
|
|||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { Theme, getBuiltinThemesRef } from '@/scripts/theme.js';
|
||||
import copyToClipboard from '@/scripts/copy-to-clipboard.js';
|
||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||
import * as os from '@/os.js';
|
||||
import { getThemes, removeTheme } from '@/theme-store.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
|
|
|||
|
|
@ -213,12 +213,18 @@ definePageMetadata(() => ({
|
|||
}
|
||||
}
|
||||
|
||||
.dn:focus-visible ~ .toggle {
|
||||
outline: 2px solid var(--focus);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 90px;
|
||||
height: 50px;
|
||||
margin: 4px; // focus用のアウトライン
|
||||
background-color: #83D8FF;
|
||||
border-radius: 90px - 6;
|
||||
transition: background-color 200ms cubic-bezier(0.445, 0.05, 0.55, 0.95) !important;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkInput>
|
||||
|
||||
<FormSection>
|
||||
<template #label>{{ i18n.ts._webhookSettings.events }}</template>
|
||||
<template #label>{{ i18n.ts._webhookSettings.trigger }}</template>
|
||||
|
||||
<div class="_gaps_s">
|
||||
<MkSwitch v-model="event_follow">{{ i18n.ts._webhookSettings._events.follow }}</MkSwitch>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkInput>
|
||||
|
||||
<FormSection>
|
||||
<template #label>{{ i18n.ts._webhookSettings.events }}</template>
|
||||
<template #label>{{ i18n.ts._webhookSettings.trigger }}</template>
|
||||
|
||||
<div class="_gaps_s">
|
||||
<MkSwitch v-model="event_follow">{{ i18n.ts._webhookSettings._events.follow }}</MkSwitch>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue