Merge branch Sharkey:develop into trackeropt

This commit is contained in:
Vavency 2025-05-09 12:34:05 +00:00
commit 000609b43d
68 changed files with 1316 additions and 902 deletions

View file

@ -1,7 +1,17 @@
This logo text was made in Inkscape by @sneexy@booping.synth.download
# Sharkey Logo
If you edit it, you can use
[svgo](https://jakearchibald.github.io/svgomg/) to generate a
browser-compatible file, to replace `../sharkey.svg`
This logo was made in Inkscape by [@sneexy@booping.synth.download](https://booping.synth.download/@sneexy).
The font used is Lilita One ([Google Fonts](https://fonts.google.com/specimen/Lilita+One)).
## Using Inkscape
Preferably, you should use Inkscape when wanting to make modifications to the logo. Once you've made your edits, save the SVG here as is from Inkscape directly, then use [svgo](https://github.com/svg/svgo) ([Web UI](https://jakearchibald.github.io/svgomg), ensure `Multipass` is enabled) to produce an SVG compatible to be viewed in web browsers, which that file will then replace [`../sharkey.svg`](../sharkey.svg).
## Not using Inkscape
The logo should preferably be modified using Inkscape, but should work in any other software. If any weird issues appear, try opening it with Inkscape first or try using the version under [`../sharkey.svg`](../sharkey.svg) if you prefer to work with your software. Follow the instructions for Using Inkscape.
## Licence
This logo is distributed under the same licence as Sharkey (AGPL ≥3).

View file

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Before After
Before After

View file

@ -92,7 +92,6 @@ SPDX-License-Identifier: AGPL-3.0-only
<button v-if="postFormActions.length > 0" v-tooltip="i18n.ts.plugins" class="_button" :class="$style.footerButton" @click="showActions"><i class="ti ti-plug"></i></button>
<button v-tooltip="i18n.ts.emoji" :class="['_button', $style.footerButton]" @click="insertEmoji"><i class="ti ti-mood-happy"></i></button>
<button v-if="showAddMfmFunction" v-tooltip="i18n.ts.addMfmFunction" :class="['_button', $style.footerButton]" @click="insertMfmFunction"><i class="ti ti-palette"></i></button>
<button v-tooltip="i18n.ts.otherSettings" :class="['_button', $style.footerButton]" @click="showOtherMenu"><i class="ti ti-dots"></i></button>
</div>
<div :class="$style.footerRight">
<button v-tooltip="i18n.ts.previewNoteText" class="_button" :class="[$style.footerButton, { [$style.previewButtonActive]: showPreview }]" @click="showPreview = !showPreview"><i class="ti ti-eye"></i></button>
@ -187,6 +186,7 @@ const posted = ref(false);
const text = ref(props.initialText ?? '');
const files = ref(props.initialFiles ?? []);
const poll = ref<PollEditorModelValue | null>(null);
const initialPoll = ref<PollEditorModelValue | null>(null);
const useCw = ref<boolean>(!!props.initialCw);
const showPreview = ref(store.s.showPreview);
watch(showPreview, () => store.set('showPreview', showPreview.value));
@ -317,19 +317,10 @@ if (props.reply && (props.reply.user.username !== $i.username || (props.reply.us
text.value = `@${props.reply.user.username}${props.reply.user.host != null ? '@' + toASCII(props.reply.user.host) : ''} `;
}
if (props.reply && props.reply.text != null) {
const ast = mfm.parse(props.reply.text);
const otherHost = props.reply.user.host;
for (const x of extractMentions(ast)) {
const mention = x.host ?
`@${x.username}@${toASCII(x.host)}` :
(otherHost == null || otherHost === host) ?
`@${x.username}` :
`@${x.username}@${toASCII(otherHost)}`;
//
if ($i.username === x.username && (x.host == null || x.host === host)) continue;
if (props.reply && props.reply.mentionHandles) {
for (const [user, mention] of Object.entries(props.reply.mentionHandles)) {
// Don't mention ourself
if (user === $i.id) continue;
//
if (text.value.includes(`${mention} `)) continue;
@ -425,7 +416,7 @@ function checkMissingMention() {
const ast = mfm.parse(text.value);
for (const x of extractMentions(ast)) {
if (!visibleUsers.value.some(u => (u.username === x.username) && (u.host === x.host))) {
if (!visibleUsers.value.some(u => (u.username.toLowerCase() === x.username.toLowerCase()) && (u.host === x.host))) {
hasNotSpecifiedMentions.value = true;
return;
}
@ -438,7 +429,7 @@ function addMissingMention() {
const ast = mfm.parse(text.value);
for (const x of extractMentions(ast)) {
if (!visibleUsers.value.some(u => (u.username === x.username) && (u.host === x.host))) {
if (!visibleUsers.value.some(u => (u.username.toLowerCase() === x.username.toLowerCase()) && (u.host === x.host))) {
misskeyApi('users/show', { username: x.username, host: x.host }).then(user => {
pushVisibleUser(user);
});
@ -629,12 +620,32 @@ function showOtherSettings() {
},
}] satisfies MenuItem[];
if ($i.policies.scheduleNoteMax > 0) {
menuItems.push({ type: 'divider' }, {
type: 'button',
text: i18n.ts.schedulePost,
icon: 'ti ti-calendar-time',
action: toggleScheduleNote,
}, {
type: 'button',
text: i18n.ts.schedulePostList,
icon: 'ti ti-calendar-event',
action: () => {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkSchedulePostListDialog.vue')), {}, {
closed: () => {
dispose();
},
});
},
});
}
os.popupMenu(menuItems, otherSettingsButton.value);
}
//#endregion
function pushVisibleUser(user: Misskey.entities.UserDetailed) {
if (!visibleUsers.value.some(u => u.username === user.username && u.host === user.host)) {
if (!visibleUsers.value.some(u => u.username.toLowerCase() === user.username.toLowerCase() && u.host === user.host)) {
visibleUsers.value.push(user);
}
}
@ -959,6 +970,15 @@ async function post(ev?: MouseEvent) {
token = storedAccounts.find(x => x.id === postAccount.value?.id)?.token;
}
if (postData.editId && postData.poll !== initialPoll.value) {
const { canceled } = await os.confirm({
type: 'warning',
title: i18n.ts._confirmPollEdit.title,
text: i18n.ts._confirmPollEdit.text,
});
if (canceled) return;
}
posting.value = true;
misskeyApi(postData.editId ? 'notes/edit' : (postData.scheduleNote ? 'notes/schedule/create' : 'notes/create'), postData, token).then(() => {
if (props.freezeAfterPosted) {
@ -1121,32 +1141,6 @@ function toggleScheduleNote() {
}
}
function showOtherMenu(ev: MouseEvent) {
const menuItems: MenuItem[] = [];
if ($i.policies.scheduleNoteMax > 0) {
menuItems.push({
type: 'button',
text: i18n.ts.schedulePost,
icon: 'ti ti-calendar-time',
action: toggleScheduleNote,
}, {
type: 'button',
text: i18n.ts.schedulePostList,
icon: 'ti ti-calendar-event',
action: () => {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkSchedulePostListDialog.vue')), {}, {
closed: () => {
dispose();
},
});
},
});
}
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
}
onMounted(() => {
if (props.autofocus) {
focus();
@ -1208,6 +1202,7 @@ onMounted(() => {
expiresAt: init.poll.expiresAt ? (new Date(init.poll.expiresAt)).getTime() : null,
expiredAfter: null,
};
if (props.editId) initialPoll.value = poll.value;
}
if (init.visibleUserIds) {
misskeyApi('users/show', { userIds: init.visibleUserIds }).then(users => {

View file

@ -203,6 +203,7 @@ const QUEUE_TYPES = [
'objectStorage',
'userWebhookDeliver',
'systemWebhookDeliver',
'scheduleNotePost',
] as const;
const tab: Ref<typeof QUEUE_TYPES[number] | '-'> = ref('-');