Merge remote-tracking branch 'misskey/master' into feature/misskey-2024.07

This commit is contained in:
dakkar 2024-08-02 12:25:58 +01:00
commit cfa9b852df
585 changed files with 23423 additions and 9623 deletions

View file

@ -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> {

View file

@ -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) {

View file

@ -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(() => []);

View file

@ -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() {

View file

@ -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(),
};
}

View file

@ -90,7 +90,7 @@ const meterStyle = computed(() => {
h: 180 - (usage.value / capacity.value * 180),
s: 0.7,
l: 0.5,
}),
}).toHslString(),
};
});

View file

@ -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();
});

View file

@ -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';

View file

@ -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',

View file

@ -481,6 +481,7 @@ definePageMetadata(() => ({
&:hover, &:focus {
opacity: .7;
}
&:active {
cursor: pointer;
}

View file

@ -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;
}

View file

@ -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,
});

View file

@ -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">

View file

@ -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';

View file

@ -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;

View file

@ -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>

View file

@ -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>