Merge remote-tracking branch 'misskey-original/develop' into develop
# Conflicts: # package.json # packages/frontend/src/components/MkFoldableSection.vue # packages/frontend/src/components/MkPostForm.vue
This commit is contained in:
commit
7579df2da0
48 changed files with 607 additions and 292 deletions
|
|
@ -435,7 +435,7 @@ function applySelect() {
|
|||
|
||||
function chooseUser() {
|
||||
props.close();
|
||||
os.selectUser().then(user => {
|
||||
os.selectUser({ includeSelf: true }).then(user => {
|
||||
complete('user', user);
|
||||
props.textarea.focus();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ function onClick(item: LegendItem) {
|
|||
if (chart.value == null) return;
|
||||
if (type.value === 'pie' || type.value === 'doughnut') {
|
||||
// Pie and doughnut charts only have a single dataset and visibility is per item
|
||||
if (item.index) chart.value.toggleDataVisibility(item.index);
|
||||
if (item.index != null) chart.value.toggleDataVisibility(item.index);
|
||||
} else {
|
||||
if (item.datasetIndex) chart.value.setDatasetVisibility(item.datasetIndex, !chart.value.isDatasetVisible(item.datasetIndex));
|
||||
if (item.datasetIndex != null) chart.value.setDatasetVisibility(item.datasetIndex, !chart.value.isDatasetVisible(item.datasetIndex));
|
||||
}
|
||||
chart.value.update();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<template>
|
||||
<div :class="['codeBlockRoot', { 'codeEditor': codeEditor }]" v-html="html"></div>
|
||||
<div :class="[$style.codeBlockRoot, { [$style.codeEditor]: codeEditor }]" v-html="html"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import { BUNDLED_LANGUAGES } from 'shiki';
|
||||
import type { Lang as ShikiLang } from 'shiki';
|
||||
import { bundledLanguagesInfo } from 'shiki';
|
||||
import type { BuiltinLanguage } from 'shiki';
|
||||
import { getHighlighter } from '@/scripts/code-highlighter.js';
|
||||
|
||||
const props = defineProps<{
|
||||
|
|
@ -22,24 +22,25 @@ const props = defineProps<{
|
|||
|
||||
const highlighter = await getHighlighter();
|
||||
|
||||
const codeLang = ref<ShikiLang | 'aiscript'>('js');
|
||||
const codeLang = ref<BuiltinLanguage | 'aiscript'>('js');
|
||||
const html = computed(() => highlighter.codeToHtml(props.code, {
|
||||
lang: codeLang.value,
|
||||
theme: 'dark-plus',
|
||||
}));
|
||||
|
||||
async function fetchLanguage(to: string): Promise<void> {
|
||||
const language = to as ShikiLang;
|
||||
const language = to as BuiltinLanguage;
|
||||
|
||||
// Check for the loaded languages, and load the language if it's not loaded yet.
|
||||
if (!highlighter.getLoadedLanguages().includes(language)) {
|
||||
// Check if the language is supported by Shiki
|
||||
const bundles = BUNDLED_LANGUAGES.filter((bundle) => {
|
||||
const bundles = bundledLanguagesInfo.filter((bundle) => {
|
||||
// Languages are specified by their id, they can also have aliases (i. e. "js" and "javascript")
|
||||
return bundle.id === language || bundle.aliases?.includes(language);
|
||||
});
|
||||
if (bundles.length > 0) {
|
||||
await highlighter.loadLanguage(language);
|
||||
console.log(`Loading language: ${language}`);
|
||||
await highlighter.loadLanguage(bundles[0].import);
|
||||
codeLang.value = language;
|
||||
} else {
|
||||
codeLang.value = 'js';
|
||||
|
|
@ -57,8 +58,8 @@ watch(() => props.lang, (to) => {
|
|||
}, { immediate: true });
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.codeBlockRoot :deep(.shiki) {
|
||||
<style module lang="scss">
|
||||
.codeBlockRoot :global(.shiki) {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
|
|
@ -74,7 +75,7 @@ watch(() => props.lang, (to) => {
|
|||
min-width: 100%;
|
||||
height: 100%;
|
||||
|
||||
& :deep(.shiki) {
|
||||
& :global(.shiki) {
|
||||
padding: 12px;
|
||||
margin: 0;
|
||||
border-radius: 6px;
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</button>
|
||||
</header>
|
||||
<Transition
|
||||
:enterActiveClass="defaultStore.state.animation ? $style.folder_toggle_enter_active : ''"
|
||||
:leaveActiveClass="defaultStore.state.animation ? $style.folder_toggle_leave_active : ''"
|
||||
:enterFromClass="defaultStore.state.animation ? $style.folder_toggle_enter_from : ''"
|
||||
:leaveToClass="defaultStore.state.animation ? $style.folder_toggle_leave_to : ''"
|
||||
:enterActiveClass="defaultStore.state.animation ? $style.folderToggleEnterActive : ''"
|
||||
:leaveActiveClass="defaultStore.state.animation ? $style.folderToggleLeaveActive : ''"
|
||||
:enterFromClass="defaultStore.state.animation ? $style.folderToggleEnterFrom : ''"
|
||||
:leaveToClass="defaultStore.state.animation ? $style.folderToggleLeaveTo : ''"
|
||||
@enter="enter"
|
||||
@afterEnter="afterEnter"
|
||||
@leave="leave"
|
||||
|
|
@ -39,9 +39,8 @@ import { defaultStore } from '@/store.js';
|
|||
const miLocalStoragePrefix = 'ui:folder:' as const;
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
expanded?: boolean;
|
||||
persistKey?: string;
|
||||
defaultOpen?: boolean;
|
||||
expanded?: boolean;
|
||||
persistKey?: string;
|
||||
}>(), {
|
||||
expanded: true,
|
||||
});
|
||||
|
|
@ -100,55 +99,50 @@ onMounted(() => {
|
|||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.folder_toggle_enter_active {
|
||||
overflow-y: clip;
|
||||
transition: opacity 0.5s, height 0.5s !important;
|
||||
}
|
||||
.folder_toggle_leave_active {
|
||||
.folderToggleEnterActive, .folderToggleLeaveActive {
|
||||
overflow-y: clip;
|
||||
transition: opacity 0.5s, height 0.5s !important;
|
||||
}
|
||||
.folder_toggle_enter_from {
|
||||
opacity: 0;
|
||||
}
|
||||
.folder_toggle_leave_to {
|
||||
|
||||
.folderToggleEnterFrom, .folderToggleLeaveTo {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.root {
|
||||
position: relative;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
position: sticky;
|
||||
top: var(--stickyTop, 0px);
|
||||
-webkit-backdrop-filter: var(--blur, blur(8px));
|
||||
backdrop-filter: var(--blur, blur(20px));
|
||||
display: flex;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
position: sticky;
|
||||
top: var(--stickyTop, 0px);
|
||||
-webkit-backdrop-filter: var(--blur, blur(8px));
|
||||
backdrop-filter: var(--blur, blur(20px));
|
||||
}
|
||||
|
||||
.title {
|
||||
display: grid;
|
||||
place-content: center;
|
||||
margin: 0;
|
||||
padding: 12px 16px 12px 0;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
margin: 0;
|
||||
padding: 12px 16px 12px 0;
|
||||
}
|
||||
|
||||
.divider {
|
||||
flex: 1;
|
||||
margin: auto;
|
||||
height: 1px;
|
||||
background: var(--divider);
|
||||
flex: 1;
|
||||
margin: auto;
|
||||
height: 1px;
|
||||
background: var(--divider);
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 12px 0 12px 16px;
|
||||
padding: 12px 0 12px 16px;
|
||||
}
|
||||
|
||||
@container (max-width: 500px) {
|
||||
.title {
|
||||
padding: 8px 10px 8px 0;
|
||||
}
|
||||
.title {
|
||||
padding: 8px 10px 8px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -396,6 +396,7 @@ onDeactivated(() => {
|
|||
|
||||
.hidden {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #000;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
|
|
|||
|
|
@ -270,7 +270,12 @@ const translation = ref<Misskey.entities.NotesTranslateResponse | null>(null);
|
|||
const translating = ref(false);
|
||||
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.value.user.instance);
|
||||
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || (appearNote.value.visibility === 'followers' && appearNote.value.userId === $i?.id));
|
||||
const renoteCollapsed = ref(defaultStore.state.collapseRenotes && isRenote && (($i && ($i.id === note.value.userId || $i.id === appearNote.value.userId)) ?? (appearNote.value.myReaction != null)));
|
||||
const renoteCollapsed = ref(
|
||||
defaultStore.state.collapseRenotes && isRenote && (
|
||||
($i && ($i.id === note.value.userId || $i.id === appearNote.value.userId)) || // `||` must be `||`! See https://github.com/misskey-dev/misskey/issues/13131
|
||||
(appearNote.value.myReaction != null)
|
||||
)
|
||||
);
|
||||
|
||||
/* Overload FunctionにLintが対応していないのでコメントアウト
|
||||
function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly: true): boolean;
|
||||
|
|
|
|||
|
|
@ -903,7 +903,7 @@ function cancel() {
|
|||
}
|
||||
|
||||
function insertMention() {
|
||||
os.selectUser().then(user => {
|
||||
os.selectUser({ localOnly: localOnly.value, includeSelf: true }).then(user => {
|
||||
insertTextAtCursor(textareaEl.value, '@' + Misskey.acct.toString(user) + ' ');
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,11 +78,14 @@ const emit = defineEmits<{
|
|||
(ev: 'closed'): void;
|
||||
}>();
|
||||
|
||||
const props = defineProps<{
|
||||
const props = withDefaults(defineProps<{
|
||||
includeSelf?: boolean;
|
||||
multiple?: boolean;
|
||||
localOnly?: boolean;
|
||||
}>();
|
||||
}>(), {
|
||||
includeSelf: false,
|
||||
localOnly: false,
|
||||
});
|
||||
|
||||
const username = ref('');
|
||||
const host = ref('');
|
||||
|
|
@ -103,7 +106,13 @@ function search() {
|
|||
limit: 10,
|
||||
detail: false,
|
||||
}).then(_users => {
|
||||
users.value = _users;
|
||||
users.value = _users.filter((u) => {
|
||||
if (props.includeSelf) {
|
||||
return true;
|
||||
} else {
|
||||
return u.id !== $i?.id;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -129,18 +138,22 @@ onMounted(() => {
|
|||
misskeyApi('users/show', {
|
||||
userIds: defaultStore.state.recentlyUsedUsers,
|
||||
}).then(foundUsers => {
|
||||
const _users = foundUsers.filter((u) => {
|
||||
let _users = foundUsers;
|
||||
_users = _users.filter((u) => {
|
||||
if (props.localOnly) {
|
||||
return u.host == null;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (props.includeSelf && _users.find(x => $i ? x.id === $i.id : true) == null) {
|
||||
recentUsers.value = [$i!, ..._users];
|
||||
} else {
|
||||
recentUsers.value = _users;
|
||||
}
|
||||
_users = _users.filter((u) => {
|
||||
if (props.includeSelf) {
|
||||
return true;
|
||||
} else {
|
||||
return u.id !== $i?.id;
|
||||
}
|
||||
});
|
||||
recentUsers.value = _users;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<img
|
||||
v-for="decoration in decorations ?? user.avatarDecorations"
|
||||
:class="[$style.decoration]"
|
||||
:src="decoration.url"
|
||||
:src="getDecorationUrl(decoration)"
|
||||
:style="{
|
||||
rotate: getDecorationAngle(decoration),
|
||||
scale: getDecorationScale(decoration),
|
||||
|
|
@ -92,6 +92,11 @@ function onClick(ev: MouseEvent): void {
|
|||
emit('click', ev);
|
||||
}
|
||||
|
||||
function getDecorationUrl(decoration: Omit<Misskey.entities.UserDetailed['avatarDecorations'][number], 'id'>) {
|
||||
if (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar) return getStaticImageUrl(decoration.url);
|
||||
return decoration.url;
|
||||
}
|
||||
|
||||
function getDecorationAngle(decoration: Omit<Misskey.entities.UserDetailed['avatarDecorations'][number], 'id'>) {
|
||||
const angle = decoration.angle ?? 0;
|
||||
return angle === 0 ? undefined : `${angle * 360}deg`;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue