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

# Conflicts:
#	packages/frontend/src/components/MkEmojiPicker.vue
#	packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
#	packages/frontend/src/pages/timeline.vue
This commit is contained in:
mattyatea 2023-12-14 21:08:18 +09:00
commit 7313e13397
102 changed files with 2914 additions and 1291 deletions

View file

@ -8,6 +8,8 @@ import getCaretCoordinates from 'textarea-caret';
import { toASCII } from 'punycode/';
import { popup } from '@/os.js';
export type SuggestionType = 'user' | 'hashtag' | 'emoji' | 'mfmTag';
export class Autocomplete {
private suggestion: {
x: Ref<number>;
@ -19,6 +21,7 @@ export class Autocomplete {
private currentType: string;
private textRef: Ref<string>;
private opening: boolean;
private onlyType: SuggestionType[];
private get text(): string {
// Use raw .value to get the latest value
@ -35,7 +38,7 @@ export class Autocomplete {
/**
*
*/
constructor(textarea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref<string>) {
constructor(textarea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref<string>, onlyType?: SuggestionType[]) {
//#region BIND
this.onInput = this.onInput.bind(this);
this.complete = this.complete.bind(this);
@ -46,6 +49,7 @@ export class Autocomplete {
this.textarea = textarea;
this.textRef = textRef;
this.opening = false;
this.onlyType = onlyType ?? ['user', 'hashtag', 'emoji', 'mfmTag'];
this.attach();
}
@ -95,7 +99,7 @@ export class Autocomplete {
let opened = false;
if (isMention) {
if (isMention && this.onlyType.includes('user')) {
const username = text.substring(mentionIndex + 1);
if (username !== '' && username.match(/^[a-zA-Z0-9_]+$/)) {
this.open('user', username);
@ -106,7 +110,7 @@ export class Autocomplete {
}
}
if (isHashtag && !opened) {
if (isHashtag && !opened && this.onlyType.includes('hashtag')) {
const hashtag = text.substring(hashtagIndex + 1);
if (!hashtag.includes(' ')) {
this.open('hashtag', hashtag);
@ -114,7 +118,7 @@ export class Autocomplete {
}
}
if (isEmoji && !opened) {
if (isEmoji && !opened && this.onlyType.includes('emoji')) {
const emoji = text.substring(emojiIndex + 1);
if (!emoji.includes(' ')) {
this.open('emoji', emoji);
@ -122,7 +126,7 @@ export class Autocomplete {
}
}
if (isMfmTag && !opened) {
if (isMfmTag && !opened && this.onlyType.includes('mfmTag')) {
const mfmTag = text.substring(mfmTagIndex + 1);
if (!mfmTag.includes(' ')) {
this.open('mfmTag', mfmTag.replace('[', ''));

View file

@ -6,6 +6,7 @@ import { fetchCustomEmojis } from '@/custom-emojis.js';
export async function clearCache() {
os.waiting();
miLocalStorage.removeItem('locale');
miLocalStorage.removeItem('localeVersion');
miLocalStorage.removeItem('theme');
miLocalStorage.removeItem('emojis');
miLocalStorage.removeItem('lastEmojisFetchedAt');

View file

@ -3,8 +3,9 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { defineAsyncComponent, Ref, ref } from 'vue';
import { defineAsyncComponent, Ref, ref, computed, ComputedRef } from 'vue';
import { popup } from '@/os.js';
import { defaultStore } from '@/store.js';
/**
*
@ -23,8 +24,10 @@ class EmojiPicker {
}
public async init() {
const emojisRef = defaultStore.reactiveState.pinnedEmojis;
await popup(defineAsyncComponent(() => import('@/components/MkEmojiPickerDialog.vue')), {
src: this.src,
pinnedEmojis: emojisRef,
asReactionPicker: false,
manualShowing: this.manualShowing,
choseAndClose: false,
@ -44,8 +47,8 @@ class EmojiPicker {
public show(
src: HTMLElement,
onChosen: EmojiPicker['onChosen'],
onClosed: EmojiPicker['onClosed'],
onChosen?: EmojiPicker['onChosen'],
onClosed?: EmojiPicker['onClosed'],
) {
this.src.value = src;
this.manualShowing.value = true;

View file

@ -398,7 +398,7 @@ export function getNoteMenu(props: {
}
if (noteActions.length > 0) {
menu = menu.concat([null, ...noteActions.map(action => ({
menu = menu.concat([{ type: "divider" }, ...noteActions.map(action => ({
icon: 'ti ti-plug',
text: action.title,
action: () => {
@ -408,7 +408,7 @@ export function getNoteMenu(props: {
}
if (defaultStore.state.devMode) {
menu = menu.concat([null, {
menu = menu.concat([{ type: "divider" }, {
icon: 'ti ti-id',
text: i18n.ts.copyNoteId,
action: () => {

View file

@ -5,6 +5,7 @@
import { defineAsyncComponent, Ref, ref } from 'vue';
import { popup } from '@/os.js';
import { defaultStore } from '@/store.js';
class ReactionPicker {
private src: Ref<HTMLElement | null> = ref(null);
@ -17,25 +18,27 @@ class ReactionPicker {
}
public async init() {
const reactionsRef = defaultStore.reactiveState.reactions;
await popup(defineAsyncComponent(() => import('@/components/MkEmojiPickerDialog.vue')), {
src: this.src,
pinnedEmojis: reactionsRef,
asReactionPicker: true,
manualShowing: this.manualShowing,
}, {
done: reaction => {
this.onChosen!(reaction);
if (this.onChosen) this.onChosen(reaction);
},
close: () => {
this.manualShowing.value = false;
},
closed: () => {
this.src.value = null;
this.onClosed!();
if (this.onClosed) this.onClosed();
},
});
}
public show(src: HTMLElement, onChosen: ReactionPicker['onChosen'], onClosed: ReactionPicker['onClosed']) {
public show(src: HTMLElement, onChosen?: ReactionPicker['onChosen'], onClosed?: ReactionPicker['onClosed']) {
this.src.value = src;
this.manualShowing.value = true;
this.onChosen = onChosen;