Merge tag '2024.10.1' into feature/2024.10

This commit is contained in:
dakkar 2024-11-08 15:52:37 +00:00
commit f079edaf3c
454 changed files with 9728 additions and 3363 deletions

View file

@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #icon><i class="ti ti-shield-lock"></i></template>
<template #label>{{ i18n.ts.totp }}</template>
<template #caption>{{ i18n.ts.totpDescription }}</template>
<template #suffix><i v-if="$i.twoFactorEnabled" class="ti ti-check" style="color: var(--success)"></i></template>
<template #suffix><i v-if="$i.twoFactorEnabled" class="ti ti-check" style="color: var(--MI_THEME-success)"></i></template>
<div v-if="$i.twoFactorEnabled" class="_gaps_s">
<div v-text="i18n.ts._2fa.alreadyRegistered"/>

View file

@ -45,7 +45,7 @@ const init = async () => {
});
};
function menu(account, ev) {
function menu(account: Misskey.entities.UserDetailed, ev: MouseEvent) {
os.popupMenu([{
text: i18n.ts.switch,
icon: 'ti ti-switch-horizontal',
@ -58,7 +58,7 @@ function menu(account, ev) {
}], ev.currentTarget ?? ev.target);
}
function addAccount(ev) {
function addAccount(ev: MouseEvent) {
os.popupMenu([{
text: i18n.ts.existingAccount,
action: () => { addExistingAccount(); },
@ -68,14 +68,14 @@ function addAccount(ev) {
}], ev.currentTarget ?? ev.target);
}
async function removeAccount(account) {
async function removeAccount(account: Misskey.entities.UserDetailed) {
await _removeAccount(account.id);
accounts.value = accounts.value.filter(x => x.id !== account.id);
}
function addExistingAccount() {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {}, {
done: async res => {
done: async (res: Misskey.entities.SigninFlowResponse & { finished: true }) => {
await addAccounts(res.id, res.i);
os.success();
init();
@ -86,17 +86,17 @@ function addExistingAccount() {
function createAccount() {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkSignupDialog.vue')), {}, {
done: async res => {
await addAccounts(res.id, res.i);
switchAccountWithToken(res.i);
done: async (res: Misskey.entities.SignupResponse) => {
await addAccounts(res.id, res.token);
switchAccountWithToken(res.token);
},
closed: () => dispose(),
});
}
async function switchAccount(account: any) {
const fetchedAccounts: any[] = await getAccounts();
const token = fetchedAccounts.find(x => x.id === account.id).token;
const fetchedAccounts = await getAccounts();
const token = fetchedAccounts.find(x => x.id === account.id)!.token;
switchAccountWithToken(token);
}

View file

@ -14,30 +14,39 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<template #default="{items}">
<div class="_gaps">
<div v-for="token in items" :key="token.id" class="_panel" :class="$style.app">
<img v-if="token.iconUrl" :class="$style.appIcon" :src="token.iconUrl" alt=""/>
<div :class="$style.appBody">
<div :class="$style.appName">{{ token.name }}</div>
<div>{{ token.description }}</div>
<MkKeyValue oneline>
<template #key>{{ i18n.ts.installedDate }}</template>
<template #value><MkTime :time="token.createdAt"/></template>
</MkKeyValue>
<MkKeyValue oneline>
<template #key>{{ i18n.ts.lastUsedDate }}</template>
<template #value><MkTime :time="token.lastUsedAt"/></template>
</MkKeyValue>
<details>
<summary>{{ i18n.ts.details }}</summary>
<MkFolder v-for="token in items" :key="token.id" :defaultOpen="true">
<template #icon>
<img v-if="token.iconUrl" :class="$style.appIcon" :src="token.iconUrl" alt=""/>
<i v-else class="ti ti-plug"/>
</template>
<template #label>{{ token.name }}</template>
<template #caption>{{ token.description }}</template>
<template #suffix><MkTime :time="token.lastUsedAt"/></template>
<template #footer>
<MkButton danger @click="revoke(token)"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
</template>
<div class="_gaps_s">
<div v-if="token.description">{{ token.description }}</div>
<div>
<MkKeyValue oneline>
<template #key>{{ i18n.ts.installedDate }}</template>
<template #value><MkTime :time="token.createdAt" :mode="'detail'"/></template>
</MkKeyValue>
<MkKeyValue oneline>
<template #key>{{ i18n.ts.lastUsedDate }}</template>
<template #value><MkTime :time="token.lastUsedAt" :mode="'detail'"/></template>
</MkKeyValue>
</div>
<MkFolder>
<template #label>{{ i18n.ts.permission }}</template>
<template #suffix>{{ Object.keys(token.permission).length === 0 ? i18n.ts.none : Object.keys(token.permission).length }}</template>
<ul>
<li v-for="p in token.permission" :key="p">{{ i18n.ts._permissions[p] }}</li>
</ul>
</details>
<div>
<MkButton inline danger @click="revoke(token)"><i class="ti ti-trash"></i></MkButton>
</div>
</MkFolder>
</div>
</div>
</MkFolder>
</div>
</template>
</FormPagination>
@ -52,6 +61,7 @@ import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkKeyValue from '@/components/MkKeyValue.vue';
import MkButton from '@/components/MkButton.vue';
import MkFolder from '@/components/MkFolder.vue';
import { infoImageUrl } from '@/instance.js';
const list = ref<InstanceType<typeof FormPagination>>();
@ -82,26 +92,9 @@ definePageMetadata(() => ({
</script>
<style lang="scss" module>
.app {
display: flex;
padding: 16px;
}
.appIcon {
display: block;
flex-shrink: 0;
margin: 0 12px 0 0;
width: 50px;
height: 50px;
border-radius: var(--radius-sm);
}
.appBody {
width: calc(100% - 62px);
position: relative;
}
.appName {
font-weight: bold;
width: 20px;
height: 20px;
border-radius: 4px;
}
</style>

View file

@ -44,7 +44,7 @@ const emit = defineEmits<{
.root {
cursor: pointer;
padding: 16px 16px 28px 16px;
border: solid 2px var(--divider);
border: solid 2px var(--MI_THEME-divider);
border-radius: var(--radius-sm);
text-align: center;
font-size: 90%;
@ -53,8 +53,8 @@ const emit = defineEmits<{
}
.active {
background-color: var(--accentedBg);
border-color: var(--accent);
background-color: var(--MI_THEME-accentedBg);
border-color: var(--MI_THEME-accent);
}
.name {

View file

@ -159,8 +159,8 @@ async function detach() {
bottom: 0;
left: 0;
padding: 12px;
border-top: solid 0.5px var(--divider);
-webkit-backdrop-filter: var(--blur, blur(15px));
backdrop-filter: var(--blur, blur(15px));
border-top: solid 0.5px var(--MI_THEME-divider);
-webkit-backdrop-filter: var(--MI-blur, blur(15px));
backdrop-filter: var(--MI-blur, blur(15px));
}
</style>

View file

@ -148,7 +148,7 @@ definePageMetadata(() => ({
.current {
padding: 16px;
border-radius: var(--radius);
border-radius: var(--MI-radius);
}
.decorations {

View file

@ -177,7 +177,7 @@ definePageMetadata(() => ({
align-items: center;
&:hover {
color: var(--accent);
color: var(--MI_THEME-accent);
}
}

View file

@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInput v-model="emailAddress" type="email" manualSave>
<template #prefix><i class="ti ti-mail"></i></template>
<template v-if="$i.email && !$i.emailVerified" #caption>{{ i18n.ts.verificationEmailSent }}</template>
<template v-else-if="emailAddress === $i.email && $i.emailVerified" #caption><i class="ti ti-check" style="color: var(--success);"></i> {{ i18n.ts.emailVerified }}</template>
<template v-else-if="emailAddress === $i.email && $i.emailVerified" #caption><i class="ti ti-check" style="color: var(--MI_THEME-success);"></i> {{ i18n.ts.emailVerified }}</template>
</MkInput>
</FormSection>

View file

@ -287,9 +287,9 @@ definePageMetadata(() => ({
<style lang="scss" module>
.tab {
margin: calc(var(--margin) / 2) 0;
padding: calc(var(--margin) / 2) 0;
background: var(--bg);
margin: calc(var(--MI-margin) / 2) 0;
padding: calc(var(--MI-margin) / 2) 0;
background: var(--MI_THEME-bg);
}
.emojis {
@ -311,6 +311,6 @@ definePageMetadata(() => ({
.editorCaption {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--fgTransparentWeak);
color: var(--MI_THEME-fgTransparentWeak);
}
</style>

View file

@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div v-if="!(narrow && currentPage?.route.name == null)" class="main">
<div class="bkzroven" style="container-type: inline-size;">
<RouterView/>
<RouterView nested/>
</div>
</div>
</div>

View file

@ -243,7 +243,7 @@ definePageMetadata(() => ({
.userItemSub {
padding: 6px 12px;
font-size: 85%;
color: var(--fgTransparentWeak);
color: var(--MI_THEME-fgTransparentWeak);
}
.userItemMainBody {

View file

@ -122,7 +122,7 @@ definePageMetadata(() => ({
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
color: var(--navFg);
color: var(--MI_THEME-navFg);
}
.itemIcon {

View file

@ -65,6 +65,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="enableCondensedLine">
<template #label>Enable condensed line</template>
</MkSwitch>
<MkSwitch v-model="skipNoteRender">
<template #label>Enable note render skipping</template>
</MkSwitch>
</div>
</MkFolder>
@ -116,9 +119,14 @@ const $i = signinRequired();
const reportError = computed(defaultStore.makeGetterSetter('reportError'));
const enableCondensedLine = computed(defaultStore.makeGetterSetter('enableCondensedLine'));
const skipNoteRender = computed(defaultStore.makeGetterSetter('skipNoteRender'));
const devMode = computed(defaultStore.makeGetterSetter('devMode'));
const defaultWithReplies = computed(defaultStore.makeGetterSetter('defaultWithReplies'));
watch(skipNoteRender, async () => {
await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true });
});
async function deleteAccount() {
{
const { canceled } = await os.confirm({

View file

@ -469,7 +469,7 @@ definePageMetadata(() => ({
<style lang="scss" module>
.buttons {
display: flex;
gap: var(--margin);
gap: var(--MI-margin);
flex-wrap: wrap;
}

View file

@ -52,14 +52,17 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkFolder>
<template #icon><i class="ti ti-list"></i></template>
<template #label>{{ i18n.ts._profile.metadataEdit }}</template>
<div :class="$style.metadataRoot">
<div :class="$style.metadataMargin">
<MkButton :disabled="fields.length >= 16" inline style="margin-right: 8px;" @click="addField"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
<MkButton v-if="!fieldEditMode" :disabled="fields.length <= 1" inline danger style="margin-right: 8px;" @click="fieldEditMode = !fieldEditMode"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
<MkButton v-else inline style="margin-right: 8px;" @click="fieldEditMode = !fieldEditMode"><i class="ti ti-arrows-sort"></i> {{ i18n.ts.rearrange }}</MkButton>
<MkButton inline primary @click="saveFields"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
<template #footer>
<div class="_buttons">
<MkButton primary @click="saveFields"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
<MkButton :disabled="fields.length >= 16" @click="addField"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
<MkButton v-if="!fieldEditMode" :disabled="fields.length <= 1" danger @click="fieldEditMode = !fieldEditMode"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
<MkButton v-else @click="fieldEditMode = !fieldEditMode"><i class="ti ti-arrows-sort"></i> {{ i18n.ts.rearrange }}</MkButton>
</div>
</template>
<div :class="$style.metadataRoot" class="_gaps_s">
<MkInfo>{{ i18n.ts._profile.verifiedLinkDescription }}</MkInfo>
<Sortable
v-model="fields"
@ -71,24 +74,20 @@ SPDX-License-Identifier: AGPL-3.0-only
@end="e => e.item.classList.remove('active')"
>
<template #item="{element, index}">
<div :class="$style.fieldDragItem">
<div v-panel :class="$style.fieldDragItem">
<button v-if="!fieldEditMode" class="_button" :class="$style.dragItemHandle" tabindex="-1"><i class="ti ti-menu"></i></button>
<button v-if="fieldEditMode" :disabled="fields.length <= 1" class="_button" :class="$style.dragItemRemove" @click="deleteField(index)"><i class="ti ti-x"></i></button>
<div :class="$style.dragItemForm">
<FormSplit :minWidth="200">
<MkInput v-model="element.name" small>
<template #label>{{ i18n.ts._profile.metadataLabel }}</template>
<MkInput v-model="element.name" small :placeholder="i18n.ts._profile.metadataLabel">
</MkInput>
<MkInput v-model="element.value" small>
<template #label>{{ i18n.ts._profile.metadataContent }}</template>
<MkInput v-model="element.value" small :placeholder="i18n.ts._profile.metadataContent">
</MkInput>
</FormSplit>
</div>
</div>
</template>
</Sortable>
<MkInfo>{{ i18n.ts._profile.verifiedLinkDescription }}</MkInfo>
</div>
</MkFolder>
<template #caption>{{ i18n.ts._profile.metadataDescription }}</template>
@ -158,6 +157,10 @@ const setMaxBirthDate = () => {
return `${y}-12-31`;
};
function assertVaildLang(lang: string | null): lang is keyof typeof langmap {
return lang != null && lang in langmap;
}
const profile = reactive({
name: $i.name,
description: $i.description,
@ -165,7 +168,7 @@ const profile = reactive({
location: $i.location,
birthday: $i.birthday,
listenbrainz: $i.listenbrainz,
lang: $i.lang,
lang: assertVaildLang($i.lang) ? $i.lang : null,
isBot: $i.isBot ?? false,
isCat: $i.isCat ?? false,
speakAsCat: $i.speakAsCat ?? false,
@ -229,6 +232,11 @@ function save() {
isBot: !!profile.isBot,
isCat: !!profile.isCat,
speakAsCat: !!profile.speakAsCat,
}, undefined, {
'0b3f9f6a-2f4d-4b1f-9fb4-49d3a2fd7191': {
title: i18n.ts.yourNameContainsProhibitedWords,
text: i18n.ts.yourNameContainsProhibitedWordsDescription,
},
});
globalEvents.emit('requestClearPageCache');
claimAchievement('profileFilled');
@ -417,7 +425,7 @@ definePageMetadata(() => ({
height: 130px;
background-size: cover;
background-position: center;
border-bottom: solid 1px var(--divider);
border-bottom: solid 1px var(--MI_THEME-divider);
overflow: clip;
}
@ -449,19 +457,11 @@ definePageMetadata(() => ({
container-type: inline-size;
}
.metadataMargin {
margin-bottom: 1.5em;
}
.fieldDragItem {
display: flex;
padding-bottom: .75em;
padding: 10px;
align-items: flex-end;
border-bottom: solid 0.5px var(--divider);
&:last-child {
border-bottom: 0;
}
border-radius: 6px;
/* (drag button) 32px + (drag button margin) 8px + (input width) 200px * 2 + (input gap) 12px = 452px */
@container (max-width: 452px) {

View file

@ -124,7 +124,7 @@ definePageMetadata(() => ({
}
&:not(:last-child) {
border-bottom: solid 0.5px var(--divider);
border-bottom: solid 0.5px var(--MI_THEME-divider);
}
> header {
@ -136,11 +136,11 @@ definePageMetadata(() => ({
margin-right: 0.75em;
&.succ {
color: var(--success);
color: var(--MI_THEME-success);
}
&.fail {
color: var(--error);
color: var(--MI_THEME-error);
}
}

View file

@ -194,7 +194,7 @@ function save() {
flex-grow: 1;
min-width: 0;
font-weight: 700;
color: var(--error);
color: var(--MI_THEME-error);
}
.fileSelectorButton {
@ -203,6 +203,6 @@ function save() {
.fileNotSelected {
font-weight: 700;
color: var(--infoWarnFg);
color: var(--MI_THEME-infoWarnFg);
}
</style>

View file

@ -204,7 +204,7 @@ definePageMetadata(() => ({
}
.dn:focus-visible ~ .toggle {
outline: 2px solid var(--focus);
outline: 2px solid var(--MI_THEME-focus);
outline-offset: 2px;
}
@ -227,12 +227,12 @@ definePageMetadata(() => ({
> .before {
left: -70px;
color: var(--accent);
color: var(--MI_THEME-accent);
}
> .after {
right: -68px;
color: var(--fg);
color: var(--MI_THEME-fg);
}
}
@ -350,11 +350,11 @@ definePageMetadata(() => ({
background-color: #749DD6;
> .before {
color: var(--fg);
color: var(--MI_THEME-fg);
}
> .after {
color: var(--accent);
color: var(--MI_THEME-accent);
}
.toggle__handler {
@ -405,14 +405,14 @@ definePageMetadata(() => ({
> .sync {
padding: 14px 16px;
border-top: solid 0.5px var(--divider);
border-top: solid 0.5px var(--MI_THEME-divider);
}
}
.rsljpzjq {
> .selects {
display: flex;
gap: 1.5em var(--margin);
gap: 1.5em var(--MI-margin);
flex-wrap: wrap;
> .select {

View file

@ -184,6 +184,6 @@ definePageMetadata(() => ({
.description {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--fgTransparentWeak);
color: var(--MI_THEME-fgTransparentWeak);
}
</style>

View file

@ -17,8 +17,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #icon>
<i v-if="webhook.active === false" class="ti ti-player-pause"></i>
<i v-else-if="webhook.latestStatus === null" class="ti ti-circle"></i>
<i v-else-if="[200, 201, 204].includes(webhook.latestStatus)" class="ti ti-check" :style="{ color: 'var(--success)' }"></i>
<i v-else class="ti ti-alert-triangle" :style="{ color: 'var(--error)' }"></i>
<i v-else-if="[200, 201, 204].includes(webhook.latestStatus)" class="ti ti-check" :style="{ color: 'var(--MI_THEME-success)' }"></i>
<i v-else class="ti ti-alert-triangle" :style="{ color: 'var(--MI_THEME-error)' }"></i>
</template>
{{ webhook.name || webhook.url }}
<template #suffix>