Merge remote-tracking branch 'misskey-original/develop' into develop

# Conflicts:
#	packages/backend/src/models/RepositoryModule.ts
#	packages/backend/src/models/_.ts
#	packages/backend/src/postgres.ts
#	packages/frontend/src/components/MkDrive.file.vue
#	packages/frontend/src/components/MkEmojiPicker.vue
#	packages/frontend/src/pages/admin/index.vue
#	packages/frontend/src/pages/user/home.vue
#	packages/frontend/src/router.ts
#	packages/frontend/src/ui/universal.vue
This commit is contained in:
mattyatea 2024-01-11 21:46:28 +09:00
commit 33507e24ff
157 changed files with 3973 additions and 2059 deletions

View file

@ -266,15 +266,24 @@ function emojiAutoComplete(query: string | null, emojiDb: EmojiDef[], max = 30):
}
const matched = new Map<string, EmojiScore>();
//
//
emojiDb.some(x => {
if (x.name.startsWith(query) && !x.aliasOf) {
matched.set(x.name, { emoji: x, score: query.length + 1 });
if (x.name === query && !matched.has(x.aliasOf ?? x.name)) {
matched.set(x.aliasOf ?? x.name, { emoji: x, score: query.length + 2 });
}
return matched.size === max;
});
//
if (matched.size < max) {
emojiDb.some(x => {
if (x.name.startsWith(query) && !x.aliasOf) {
matched.set(x.name, { emoji: x, score: query.length + 1 });
}
return matched.size === max;
});
}
//
if (matched.size < max) {
emojiDb.some(x => {

View file

@ -45,10 +45,10 @@ import bytes from '@/filters/bytes.js';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { $i } from '@/account.js';
import { useRouter } from '@/router.js';
import { getDriveFileMenu, getDriveMultiFileMenu } from '@/scripts/get-drive-file-menu.js';
import { isTouchUsing } from '@/scripts/touch.js';
import { deviceKind } from '@/scripts/device-kind.js';
import { useRouter } from '@/global/router/supplier.js';
const router = useRouter();

View file

@ -226,7 +226,18 @@ watch(q, () => {
}
}
} else {
for (const emoji of emojis) {
if (customEmojisMap.has(newQ)) {
matches.add(customEmojisMap.get(newQ)!);
}
if (matches.size >= max) return matches;
for (const emoji of emojis) {
if (emoji.aliases.some(alias => alias === newQ)) {
matches.add(emoji);
if (matches.size >= max) break;
}
}
if (matches.size >= max) return matches;for (const emoji of emojis) {
if (emoji.name.startsWith(newQ)) {
matches.add(emoji);
if (matches.size >= max) break;

View file

@ -352,7 +352,7 @@ function react(viaKeyboard = false): void {
pleaseLogin();
showMovedDialog();
if (appearNote.value.reactionAcceptance === 'likeOnly') {
sound.play('reaction');
sound.playMisskeySfx('reaction');
if (props.mock) {
return;
@ -372,7 +372,7 @@ function react(viaKeyboard = false): void {
} else {
blur();
reactionPicker.show(reactButton.value, reaction => {
sound.play('reaction');
sound.playMisskeySfx('reaction');
if (props.mock) {
emit('reaction', reaction);

View file

@ -396,7 +396,7 @@ function react(viaKeyboard = false): void {
pleaseLogin();
showMovedDialog();
if (appearNote.value.reactionAcceptance === 'likeOnly') {
sound.play('reaction');
sound.playMisskeySfx('reaction');
misskeyApi('notes/reactions/create', {
noteId: appearNote.value.id,
@ -412,7 +412,7 @@ function react(viaKeyboard = false): void {
} else {
blur();
reactionPicker.show(reactButton.value, reaction => {
sound.play('reaction');
sound.playMisskeySfx('reaction');
misskeyApi('notes/reactions/create', {
noteId: appearNote.value.id,

View file

@ -23,26 +23,26 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<div ref="contents" :class="$style.root" style="container-type: inline-size;">
<RouterView :key="reloadCount" :router="router"/>
<RouterView :key="reloadCount" :router="windowRouter"/>
</div>
</MkWindow>
</template>
<script lang="ts" setup>
import { ComputedRef, onMounted, onUnmounted, provide, shallowRef, ref, computed } from 'vue';
import { computed, ComputedRef, onMounted, onUnmounted, provide, ref, shallowRef } from 'vue';
import RouterView from '@/components/global/RouterView.vue';
import MkWindow from '@/components/MkWindow.vue';
import { popout as _popout } from '@/scripts/popout.js';
import copyToClipboard from '@/scripts/copy-to-clipboard.js';
import { url } from '@/config.js';
import { mainRouter, routes, page } from '@/router.js';
import { $i } from '@/account.js';
import { Router, useScrollPositionManager } from '@/nirax.js';
import { useScrollPositionManager } from '@/nirax.js';
import { i18n } from '@/i18n.js';
import { PageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata.js';
import { openingWindowsCount } from '@/os.js';
import { claimAchievement } from '@/scripts/achievements.js';
import { getScrollContainer } from '@/scripts/scroll.js';
import { useRouterFactory } from '@/global/router/supplier.js';
import { mainRouter } from '@/global/router/main.js';
const props = defineProps<{
initialPath: string;
@ -52,14 +52,15 @@ defineEmits<{
(ev: 'closed'): void;
}>();
const router = new Router(routes, props.initialPath, !!$i, page(() => import('@/pages/not-found.vue')));
const routerFactory = useRouterFactory();
const windowRouter = routerFactory(props.initialPath);
const contents = shallowRef<HTMLElement>();
const pageMetadata = ref<null | ComputedRef<PageMetadata>>();
const windowEl = shallowRef<InstanceType<typeof MkWindow>>();
const history = ref<{ path: string; key: any; }[]>([{
path: router.getCurrentPath(),
key: router.getCurrentKey(),
path: windowRouter.getCurrentPath(),
key: windowRouter.getCurrentKey(),
}]);
const buttonsLeft = computed(() => {
const buttons = [];
@ -88,11 +89,11 @@ const buttonsRight = computed(() => {
});
const reloadCount = ref(0);
router.addListener('push', ctx => {
windowRouter.addListener('push', ctx => {
history.value.push({ path: ctx.path, key: ctx.key });
});
provide('router', router);
provide('router', windowRouter);
provideMetadataReceiver((info) => {
pageMetadata.value = info;
});
@ -112,20 +113,20 @@ const contextmenu = computed(() => ([{
icon: 'ti ti-external-link',
text: i18n.ts.openInNewTab,
action: () => {
window.open(url + router.getCurrentPath(), '_blank', 'noopener');
window.open(url + windowRouter.getCurrentPath(), '_blank', 'noopener');
windowEl.value.close();
},
}, {
icon: 'ti ti-link',
text: i18n.ts.copyLink,
action: () => {
copyToClipboard(url + router.getCurrentPath());
copyToClipboard(url + windowRouter.getCurrentPath());
},
}]));
function back() {
history.value.pop();
router.replace(history.value.at(-1)!.path, history.value.at(-1)!.key);
windowRouter.replace(history.value.at(-1)!.path, history.value.at(-1)!.key);
}
function reload() {
@ -137,16 +138,16 @@ function close() {
}
function expand() {
mainRouter.push(router.getCurrentPath(), 'forcePage');
mainRouter.push(windowRouter.getCurrentPath(), 'forcePage');
windowEl.value.close();
}
function popout() {
_popout(router.getCurrentPath(), windowEl.value.$el);
_popout(windowRouter.getCurrentPath(), windowEl.value.$el);
windowEl.value.close();
}
useScrollPositionManager(() => getScrollContainer(contents.value), router);
useScrollPositionManager(() => getScrollContainer(contents.value), windowRouter);
onMounted(() => {
openingWindowsCount.value++;

View file

@ -47,6 +47,7 @@ const props = withDefaults(defineProps<{
const emit = defineEmits<{
(ev: 'update:modelValue', value: number): void;
(ev: 'dragEnded', value: number): void;
}>();
const containerEl = shallowRef<HTMLElement>();
@ -147,6 +148,7 @@ const onMousedown = (ev: MouseEvent | TouchEvent) => {
//
if (beforeValue !== finalValue.value) {
emit('update:modelValue', finalValue.value);
emit('dragEnded', finalValue.value);
}
};

View file

@ -64,7 +64,7 @@ async function toggleReaction() {
if (confirm.canceled) return;
if (oldReaction !== props.reaction) {
sound.play('reaction');
sound.playMisskeySfx('reaction');
}
if (mock) {
@ -83,7 +83,7 @@ async function toggleReaction() {
}
});
} else {
sound.play('reaction');
sound.playMisskeySfx('reaction');
if (mock) {
emit('reactionToggled', props.reaction, (props.count + 1));

View file

@ -81,7 +81,7 @@ function prepend(note) {
emit('note');
if (props.sound) {
sound.play($i && (note.userId === $i.id) ? 'noteMy' : 'note');
sound.playMisskeySfx($i && (note.userId === $i.id) ? 'noteMy' : 'note');
}
}

View file

@ -33,7 +33,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton inline @click="enableAll">{{ i18n.ts.enableAll }}</MkButton>
</div>
<div class="_gaps_s">
<MkSwitch v-for="kind in Object.keys(permissions)" :key="kind" v-model="permissions[kind]">{{ i18n.t(`_permissions.${kind}`) }}</MkSwitch>
<MkSwitch v-for="kind in Object.keys(permissionSwitches)" :key="kind" v-model="permissionSwitches[kind]">{{ i18n.t(`_permissions.${kind}`) }}</MkSwitch>
</div>
<div v-if="iAmAdmin" :class="$style.adminPermissions">
<div :class="$style.adminPermissionsHeader"><b>{{ i18n.ts.adminPermission }}</b></div>
<div class="_gaps_s">
<MkSwitch v-for="kind in Object.keys(permissionSwitchesForAdmin)" :key="kind" v-model="permissionSwitchesForAdmin[kind]">{{ i18n.t(`_permissions.${kind}`) }}</MkSwitch>
</div>
</div>
</div>
</MkSpacer>
@ -49,6 +55,7 @@ import MkButton from './MkButton.vue';
import MkInfo from './MkInfo.vue';
import MkModalWindow from '@/components/MkModalWindow.vue';
import { i18n } from '@/i18n.js';
import { iAmAdmin } from '@/account.js';
const props = withDefaults(defineProps<{
title?: string | null;
@ -68,37 +75,76 @@ const emit = defineEmits<{
}>();
const defaultPermissions = Misskey.permissions.filter(p => !p.startsWith('read:admin') && !p.startsWith('write:admin'));
const adminPermissions = Misskey.permissions.filter(p => p.startsWith('read:admin') || p.startsWith('write:admin'));
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
const name = ref(props.initialName);
const permissions = ref(<Record<(typeof Misskey.permissions)[number], boolean>>{});
const permissionSwitches = ref(<Record<(typeof Misskey.permissions)[number], boolean>>{});
const permissionSwitchesForAdmin = ref(<Record<(typeof Misskey.permissions)[number], boolean>>{});
if (props.initialPermissions) {
for (const kind of props.initialPermissions) {
permissions.value[kind] = true;
permissionSwitches.value[kind] = true;
}
} else {
for (const kind of defaultPermissions) {
permissions.value[kind] = false;
permissionSwitches.value[kind] = false;
}
if (iAmAdmin) {
for (const kind of adminPermissions) {
permissionSwitchesForAdmin.value[kind] = false;
}
}
}
function ok(): void {
emit('done', {
name: name.value,
permissions: Object.keys(permissions.value).filter(p => permissions.value[p]),
permissions: [
...Object.keys(permissionSwitches.value).filter(p => permissionSwitches.value[p]),
...(iAmAdmin ? Object.keys(permissionSwitchesForAdmin.value).filter(p => permissionSwitchesForAdmin.value[p]) : []),
],
});
dialog.value?.close();
}
function disableAll(): void {
for (const p in permissions.value) {
permissions.value[p] = false;
for (const p in permissionSwitches.value) {
permissionSwitches.value[p] = false;
}
if (iAmAdmin) {
for (const p in permissionSwitchesForAdmin.value) {
permissionSwitchesForAdmin.value[p] = false;
}
}
}
function enableAll(): void {
for (const p in permissions.value) {
permissions.value[p] = true;
for (const p in permissionSwitches.value) {
permissionSwitches.value[p] = true;
}
if (iAmAdmin) {
for (const p in permissionSwitchesForAdmin.value) {
permissionSwitchesForAdmin.value[p] = true;
}
}
}
</script>
<style module lang="scss">
.adminPermissions {
margin: 8px -6px 0;
padding: 24px 6px 6px;
border: 2px solid var(--error);
border-radius: calc(var(--radius) / 2);
}
.adminPermissionsHeader {
margin: -34px 0 6px 12px;
padding: 0 4px;
width: fit-content;
color: var(--error);
background: var(--panel);
}
</style>

View file

@ -15,7 +15,7 @@ import * as os from '@/os.js';
import copyToClipboard from '@/scripts/copy-to-clipboard.js';
import { url } from '@/config.js';
import { i18n } from '@/i18n.js';
import { useRouter } from '@/router.js';
import { useRouter } from '@/global/router/supplier.js';
const props = withDefaults(defineProps<{
to: string;

View file

@ -99,7 +99,7 @@ function onClick(ev: MouseEvent) {
icon: 'ti ti-plus',
action: () => {
react(`:${props.name}:`);
sound.play('reaction');
sound.playMisskeySfx('reaction');
},
}] : [])], ev.currentTarget ?? ev.target);
}

View file

@ -55,7 +55,7 @@ function onClick(ev: MouseEvent) {
icon: 'ti ti-plus',
action: () => {
react(props.emoji);
sound.play('reaction');
sound.playMisskeySfx('reaction');
},
}] : [])], ev.currentTarget ?? ev.target);
}

View file

@ -16,12 +16,12 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
import { inject, onBeforeUnmount, provide, shallowRef, ref } from 'vue';
import { Resolved, Router } from '@/nirax.js';
import { inject, onBeforeUnmount, provide, ref, shallowRef } from 'vue';
import { IRouter, Resolved } from '@/nirax.js';
import { defaultStore } from '@/store.js';
const props = defineProps<{
router?: Router;
router?: IRouter;
}>();
const router = props.router ?? inject('router');