mirror of
https://activitypub.software/TransFem-org/Sharkey
synced 2024-11-21 21:45:11 +00:00
Merge branch 'develop' into feature/2024.9.0
This commit is contained in:
commit
02d36c4518
10 changed files with 102 additions and 62 deletions
|
@ -121,6 +121,7 @@ inChannelQuote: "Channel-only Quote"
|
|||
renoteToChannel: "Renote to channel"
|
||||
renoteToOtherChannel: "Renote to other channel"
|
||||
pinnedNote: "Pinned note"
|
||||
pinnedOnly: "Pinned"
|
||||
pinned: "Pin to profile"
|
||||
you: "You"
|
||||
clickToShow: "Click to show"
|
||||
|
@ -1268,7 +1269,8 @@ alwaysConfirmFollow: "Always confirm when following"
|
|||
inquiry: "Contact"
|
||||
tryAgain: "Please try again later"
|
||||
confirmWhenRevealingSensitiveMedia: "Confirm when revealing sensitive media"
|
||||
sensitiveMediaRevealConfirm: "This might be a sensitive media. Are you sure to reveal?"
|
||||
sensitiveMediaRevealConfirm: "This media might be sensitive. Are you sure you want to reveal it?"
|
||||
warnExternalUrl: "Show warning when opening external URLs"
|
||||
createdLists: "Created lists"
|
||||
createdAntennas: "Created antennas"
|
||||
fromX: "From {x}"
|
||||
|
|
8
locales/index.d.ts
vendored
8
locales/index.d.ts
vendored
|
@ -502,6 +502,10 @@ export interface Locale extends ILocale {
|
|||
* ピン留めされたノート
|
||||
*/
|
||||
"pinnedNote": string;
|
||||
/**
|
||||
* Pinned
|
||||
*/
|
||||
"pinnedOnly": string;
|
||||
/**
|
||||
* ピン留め
|
||||
*/
|
||||
|
@ -5103,6 +5107,10 @@ export interface Locale extends ILocale {
|
|||
* This media might be sensitive. Are you sure you want to reveal it?
|
||||
*/
|
||||
"sensitiveMediaRevealConfirm": string;
|
||||
/**
|
||||
* 外部URLを開く際に警告を表示する
|
||||
*/
|
||||
"warnExternalUrl": string;
|
||||
/**
|
||||
* 作成したリスト
|
||||
*/
|
||||
|
|
|
@ -121,6 +121,7 @@ inChannelQuote: "チャンネル内引用"
|
|||
renoteToChannel: "チャンネルにリノート"
|
||||
renoteToOtherChannel: "他のチャンネルにリノート"
|
||||
pinnedNote: "ピン留めされたノート"
|
||||
pinnedOnly: "Pinned"
|
||||
pinned: "ピン留め"
|
||||
you: "あなた"
|
||||
clickToShow: "クリックして表示"
|
||||
|
@ -1271,6 +1272,7 @@ inquiry: "お問い合わせ"
|
|||
tryAgain: "もう一度お試しください。"
|
||||
confirmWhenRevealingSensitiveMedia: "センシティブなメディアを表示するとき確認する"
|
||||
sensitiveMediaRevealConfirm: "センシティブなメディアです。表示しますか?"
|
||||
warnExternalUrl: "外部URLを開く際に警告を表示する"
|
||||
createdLists: "作成したリスト"
|
||||
createdAntennas: "作成したアンテナ"
|
||||
fromX: "{x}から"
|
||||
|
|
|
@ -128,20 +128,30 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
) {
|
||||
this.logger = this.queueLoggerService.logger;
|
||||
|
||||
function renderError(e: Error): any {
|
||||
if (e) { // 何故かeがundefinedで来ることがある
|
||||
function renderError(e?: Error) {
|
||||
// 何故かeがundefinedで来ることがある
|
||||
if (!e) return '?';
|
||||
|
||||
if (e instanceof Bull.UnrecoverableError || e.name === 'AbortError') {
|
||||
return `${e.name}: ${e.message}`;
|
||||
}
|
||||
|
||||
return {
|
||||
stack: e.stack,
|
||||
message: e.message,
|
||||
name: e.name,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
stack: '?',
|
||||
message: '?',
|
||||
name: '?',
|
||||
};
|
||||
}
|
||||
|
||||
function renderJob(job?: Bull.Job) {
|
||||
if (!job) return '?';
|
||||
|
||||
return {
|
||||
name: job.name || undefined,
|
||||
info: getJobInfo(job),
|
||||
failedReason: job.failedReason || undefined,
|
||||
data: job.data,
|
||||
};
|
||||
}
|
||||
|
||||
//#region system
|
||||
|
@ -176,15 +186,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
.on('active', (job) => logger.debug(`active id=${job.id}`))
|
||||
.on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`))
|
||||
.on('failed', (job, err: Error) => {
|
||||
logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) });
|
||||
logger.error(`failed(${err.name}: ${err.message}) id=${job?.id ?? '?'}`, { job: renderJob(job), e: renderError(err) });
|
||||
if (config.sentryForBackend) {
|
||||
Sentry.captureMessage(`Queue: System: ${job?.name ?? '?'}: ${err.message}`, {
|
||||
Sentry.captureMessage(`Queue: System: ${job?.name ?? '?'}: ${err.name}: ${err.message}`, {
|
||||
level: 'error',
|
||||
extra: { job, err },
|
||||
});
|
||||
}
|
||||
})
|
||||
.on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
|
||||
.on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
|
||||
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
|
||||
}
|
||||
//#endregion
|
||||
|
@ -241,15 +251,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
.on('active', (job) => logger.debug(`active id=${job.id}`))
|
||||
.on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`))
|
||||
.on('failed', (job, err) => {
|
||||
logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) });
|
||||
logger.error(`failed(${err.name}: ${err.message}) id=${job?.id ?? '?'}`, { job: renderJob(job), e: renderError(err) });
|
||||
if (config.sentryForBackend) {
|
||||
Sentry.captureMessage(`Queue: DB: ${job?.name ?? '?'}: ${err.message}`, {
|
||||
Sentry.captureMessage(`Queue: DB: ${job?.name ?? '?'}: ${err.name}: ${err.message}`, {
|
||||
level: 'error',
|
||||
extra: { job, err },
|
||||
});
|
||||
}
|
||||
})
|
||||
.on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
|
||||
.on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
|
||||
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
|
||||
}
|
||||
//#endregion
|
||||
|
@ -281,15 +291,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
.on('active', (job) => logger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`))
|
||||
.on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`))
|
||||
.on('failed', (job, err) => {
|
||||
logger.error(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
|
||||
logger.error(`failed(${err.name}: ${err.message}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
|
||||
if (config.sentryForBackend) {
|
||||
Sentry.captureMessage(`Queue: Deliver: ${err.message}`, {
|
||||
Sentry.captureMessage(`Queue: Deliver: ${err.name}: ${err.message}`, {
|
||||
level: 'error',
|
||||
extra: { job, err },
|
||||
});
|
||||
}
|
||||
})
|
||||
.on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
|
||||
.on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
|
||||
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
|
||||
}
|
||||
//#endregion
|
||||
|
@ -321,15 +331,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
.on('active', (job) => logger.debug(`active ${getJobInfo(job, true)}`))
|
||||
.on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)}`))
|
||||
.on('failed', (job, err) => {
|
||||
logger.error(`failed(${err.stack}) ${getJobInfo(job)} activity=${job ? (job.data.activity ? job.data.activity.id : 'none') : '-'}`, { job, e: renderError(err) });
|
||||
logger.error(`failed(${err.name}: ${err.message}) ${getJobInfo(job)} activity=${job ? (job.data.activity ? job.data.activity.id : 'none') : '-'}`, { job: renderJob(job), e: renderError(err) });
|
||||
if (config.sentryForBackend) {
|
||||
Sentry.captureMessage(`Queue: Inbox: ${err.message}`, {
|
||||
Sentry.captureMessage(`Queue: Inbox: ${err.name}: ${err.message}`, {
|
||||
level: 'error',
|
||||
extra: { job, err },
|
||||
});
|
||||
}
|
||||
})
|
||||
.on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
|
||||
.on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
|
||||
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
|
||||
}
|
||||
//#endregion
|
||||
|
@ -361,15 +371,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
.on('active', (job) => logger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`))
|
||||
.on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`))
|
||||
.on('failed', (job, err) => {
|
||||
logger.error(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
|
||||
logger.error(`failed(${err.name}: ${err.message}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
|
||||
if (config.sentryForBackend) {
|
||||
Sentry.captureMessage(`Queue: UserWebhookDeliver: ${err.message}`, {
|
||||
Sentry.captureMessage(`Queue: UserWebhookDeliver: ${err.name}: ${err.message}`, {
|
||||
level: 'error',
|
||||
extra: { job, err },
|
||||
});
|
||||
}
|
||||
})
|
||||
.on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
|
||||
.on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
|
||||
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
|
||||
}
|
||||
//#endregion
|
||||
|
@ -401,15 +411,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
.on('active', (job) => logger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`))
|
||||
.on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`))
|
||||
.on('failed', (job, err) => {
|
||||
logger.error(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
|
||||
logger.error(`failed(${err.name}: ${err.message}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
|
||||
if (config.sentryForBackend) {
|
||||
Sentry.captureMessage(`Queue: SystemWebhookDeliver: ${err.message}`, {
|
||||
Sentry.captureMessage(`Queue: SystemWebhookDeliver: ${err.name}: ${err.message}`, {
|
||||
level: 'error',
|
||||
extra: { job, err },
|
||||
});
|
||||
}
|
||||
})
|
||||
.on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
|
||||
.on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
|
||||
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
|
||||
}
|
||||
//#endregion
|
||||
|
@ -448,15 +458,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
.on('active', (job) => logger.debug(`active id=${job.id}`))
|
||||
.on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`))
|
||||
.on('failed', (job, err) => {
|
||||
logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) });
|
||||
logger.error(`failed(${err.name}: ${err.message}) id=${job?.id ?? '?'}`, { job: renderJob(job), e: renderError(err) });
|
||||
if (config.sentryForBackend) {
|
||||
Sentry.captureMessage(`Queue: Relationship: ${job?.name ?? '?'}: ${err.message}`, {
|
||||
Sentry.captureMessage(`Queue: Relationship: ${job?.name ?? '?'}: ${err.name}: ${err.message}`, {
|
||||
level: 'error',
|
||||
extra: { job, err },
|
||||
});
|
||||
}
|
||||
})
|
||||
.on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
|
||||
.on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
|
||||
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
|
||||
}
|
||||
//#endregion
|
||||
|
@ -489,15 +499,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
.on('active', (job) => logger.debug(`active id=${job.id}`))
|
||||
.on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`))
|
||||
.on('failed', (job, err) => {
|
||||
logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) });
|
||||
logger.error(`failed(${err.name}: ${err.message}) id=${job?.id ?? '?'}`, { job: renderJob(job), e: renderError(err) });
|
||||
if (config.sentryForBackend) {
|
||||
Sentry.captureMessage(`Queue: ObjectStorage: ${job?.name ?? '?'}: ${err.message}`, {
|
||||
Sentry.captureMessage(`Queue: ObjectStorage: ${job?.name ?? '?'}: ${err.name}: ${err.message}`, {
|
||||
level: 'error',
|
||||
extra: { job, err },
|
||||
});
|
||||
}
|
||||
})
|
||||
.on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
|
||||
.on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
|
||||
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
|
||||
}
|
||||
//#endregion
|
||||
|
|
|
@ -233,7 +233,7 @@ watch(q, () => {
|
|||
|
||||
// 名前にキーワードが含まれている
|
||||
for (const emoji of emojis) {
|
||||
if (keywords.every(keyword => emoji.name.includes(keyword))) {
|
||||
if (keywords.every(keyword => emoji.name.toLowerCase().includes(keyword))) {
|
||||
matches.add(emoji);
|
||||
if (matches.size >= max) break;
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ watch(q, () => {
|
|||
|
||||
// 名前またはエイリアスにキーワードが含まれている
|
||||
for (const emoji of emojis) {
|
||||
if (keywords.every(keyword => emoji.name.includes(keyword) || emoji.aliases.some(alias => alias.includes(keyword)))) {
|
||||
if (keywords.every(keyword => emoji.name.toLowerCase().includes(keyword) || emoji.aliases.some(alias => alias.toLowerCase().includes(keyword)))) {
|
||||
matches.add(emoji);
|
||||
if (matches.size >= max) break;
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ watch(q, () => {
|
|||
if (matches.size >= max) return matches;
|
||||
|
||||
for (const emoji of emojis) {
|
||||
if (emoji.aliases.some(alias => alias === newQ)) {
|
||||
if (emoji.aliases.some(alias => alias.toLowerCase() === newQ)) {
|
||||
matches.add(emoji);
|
||||
if (matches.size >= max) break;
|
||||
}
|
||||
|
@ -262,7 +262,7 @@ watch(q, () => {
|
|||
if (matches.size >= max) return matches;
|
||||
|
||||
for (const emoji of emojis) {
|
||||
if (emoji.name.startsWith(newQ)) {
|
||||
if (emoji.name.toLowerCase().startsWith(newQ)) {
|
||||
matches.add(emoji);
|
||||
if (matches.size >= max) break;
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ watch(q, () => {
|
|||
if (matches.size >= max) return matches;
|
||||
|
||||
for (const emoji of emojis) {
|
||||
if (emoji.aliases.some(alias => alias.startsWith(newQ))) {
|
||||
if (emoji.aliases.some(alias => alias.toLowerCase().startsWith(newQ))) {
|
||||
matches.add(emoji);
|
||||
if (matches.size >= max) break;
|
||||
}
|
||||
|
@ -278,7 +278,7 @@ watch(q, () => {
|
|||
if (matches.size >= max) return matches;
|
||||
|
||||
for (const emoji of emojis) {
|
||||
if (emoji.name.includes(newQ)) {
|
||||
if (emoji.name.toLowerCase().includes(newQ)) {
|
||||
matches.add(emoji);
|
||||
if (matches.size >= max) break;
|
||||
}
|
||||
|
@ -286,7 +286,7 @@ watch(q, () => {
|
|||
if (matches.size >= max) return matches;
|
||||
|
||||
for (const emoji of emojis) {
|
||||
if (emoji.aliases.some(alias => alias.includes(newQ))) {
|
||||
if (emoji.aliases.some(alias => alias.toLowerCase().includes(newQ))) {
|
||||
matches.add(emoji);
|
||||
if (matches.size >= max) break;
|
||||
}
|
||||
|
|
|
@ -238,11 +238,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkSwitch v-model="enableInfiniteScroll">{{ i18n.ts.enableInfiniteScroll }}</MkSwitch>
|
||||
<MkSwitch v-model="keepScreenOn">{{ i18n.ts.keepScreenOn }}</MkSwitch>
|
||||
<MkSwitch v-model="clickToOpen">{{ i18n.ts.clickToOpen }}</MkSwitch>
|
||||
<MkSwitch v-model="showBots">{{ i18n.ts.showBots }}</MkSwitch>
|
||||
<MkSwitch v-model="disableStreamingTimeline">{{ i18n.ts.disableStreamingTimeline }}</MkSwitch>
|
||||
<MkSwitch v-model="enableHorizontalSwipe">{{ i18n.ts.enableHorizontalSwipe }}</MkSwitch>
|
||||
<MkSwitch v-model="alwaysConfirmFollow">{{ i18n.ts.alwaysConfirmFollow }}</MkSwitch>
|
||||
<MkSwitch v-model="confirmWhenRevealingSensitiveMedia">{{ i18n.ts.confirmWhenRevealingSensitiveMedia }}</MkSwitch>
|
||||
<MkSwitch v-model="warnExternalUrl">{{ i18n.ts.warnExternalUrl }}</MkSwitch>
|
||||
</div>
|
||||
<MkSelect v-model="serverDisconnectedBehavior">
|
||||
<template #label>{{ i18n.ts.whenServerDisconnected }}</template>
|
||||
|
@ -380,14 +380,6 @@ const limitWidthOfReaction = computed(defaultStore.makeGetterSetter('limitWidthO
|
|||
const collapseRenotes = computed(defaultStore.makeGetterSetter('collapseRenotes'));
|
||||
const collapseNotesRepliedTo = computed(defaultStore.makeGetterSetter('collapseNotesRepliedTo'));
|
||||
const clickToOpen = computed(defaultStore.makeGetterSetter('clickToOpen'));
|
||||
// copied from src/pages/timeline.vue
|
||||
const showBots = computed<boolean>({
|
||||
get: () => defaultStore.reactiveState.tl.value.filter.withBots,
|
||||
set: (newValue) => {
|
||||
const out = deepMerge({ filter: { withBots: newValue } }, defaultStore.state.tl);
|
||||
defaultStore.set('tl', out);
|
||||
},
|
||||
});
|
||||
const collapseFiles = computed(defaultStore.makeGetterSetter('collapseFiles'));
|
||||
const autoloadConversation = computed(defaultStore.makeGetterSetter('autoloadConversation'));
|
||||
const reduceAnimation = computed(defaultStore.makeGetterSetter('animation', v => !v, v => !v));
|
||||
|
@ -440,6 +432,7 @@ const useNativeUIForVideoAudioPlayer = computed(defaultStore.makeGetterSetter('u
|
|||
const alwaysConfirmFollow = computed(defaultStore.makeGetterSetter('alwaysConfirmFollow'));
|
||||
const confirmWhenRevealingSensitiveMedia = computed(defaultStore.makeGetterSetter('confirmWhenRevealingSensitiveMedia'));
|
||||
const contextMenu = computed(defaultStore.makeGetterSetter('contextMenu'));
|
||||
const warnExternalUrl = computed(defaultStore.makeGetterSetter('warnExternalUrl'));
|
||||
|
||||
watch(lang, () => {
|
||||
miLocalStorage.setItem('lang', lang.value as string);
|
||||
|
@ -501,6 +494,7 @@ watch([
|
|||
alwaysConfirmFollow,
|
||||
confirmWhenRevealingSensitiveMedia,
|
||||
contextMenu,
|
||||
warnExternalUrl,
|
||||
], async () => {
|
||||
await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true });
|
||||
});
|
||||
|
|
|
@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<div :class="$style.tl">
|
||||
<MkTimeline
|
||||
ref="tlComponent"
|
||||
:key="src + withRenotes + withReplies + onlyFiles"
|
||||
:key="src + withRenotes + withBots + withReplies + onlyFiles"
|
||||
:src="src.split(':')[0]"
|
||||
:list="src.split(':')[1]"
|
||||
:withRenotes="withRenotes"
|
||||
|
@ -273,6 +273,10 @@ const headerActions = computed(() => {
|
|||
type: 'switch',
|
||||
text: i18n.ts.showRenotes,
|
||||
ref: withRenotes,
|
||||
}, {
|
||||
type: 'switch',
|
||||
text: i18n.ts.showBots,
|
||||
ref: withBots,
|
||||
});
|
||||
|
||||
if (isBasicTimeline(src.value) && hasWithReplies(src.value)) {
|
||||
|
|
|
@ -130,10 +130,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
|
||||
<div class="contents _gaps">
|
||||
<div v-if="user.pinnedNotes.length > 0" class="_gaps">
|
||||
<MkNote v-for="note in user.pinnedNotes" :key="note.id" class="note _panel" :note="note" :pinned="true"/>
|
||||
</div>
|
||||
<MkInfo v-else-if="$i && $i.id === user.id">{{ i18n.ts.userPagePinTip }}</MkInfo>
|
||||
<MkInfo v-if="user.pinnedNotes.length === 0 && $i?.id === user.id">{{ i18n.ts.userPagePinTip }}</MkInfo>
|
||||
<template v-if="narrow">
|
||||
<MkLazy>
|
||||
<XFiles :key="user.id" :user="user"/>
|
||||
|
@ -152,14 +149,27 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div> -->
|
||||
<MkStickyContainer>
|
||||
<template #header>
|
||||
<!-- You can't use v-if on these, as MkTab first *deletes* and replaces all children with native HTML elements. -->
|
||||
<!-- Instead, we add a "no notes" placeholder and default to null (all notes) if there's nothing pinned. -->
|
||||
<!-- It also converts all comments into text! -->
|
||||
<MkTab v-model="noteview" :class="$style.tab">
|
||||
<option value="pinned">{{ i18n.ts.pinnedOnly }}</option>
|
||||
<option :value="null">{{ i18n.ts.notes }}</option>
|
||||
<option value="all">{{ i18n.ts.all }}</option>
|
||||
<option value="files">{{ i18n.ts.withFiles }}</option>
|
||||
</MkTab>
|
||||
</template>
|
||||
<MkLazy>
|
||||
<MkNotes :class="$style.tl" :noGap="true" :pagination="AllPagination"/>
|
||||
<div v-if="noteview === 'pinned'" class="_gaps">
|
||||
<div v-if="user.pinnedNotes.length < 1" class="_fullinfo">
|
||||
<img :src="infoImageUrl" class="_ghost" aria-hidden="true" :alt="i18n.ts.noNotes"/>
|
||||
<div>{{ i18n.ts.noNotes }}</div>
|
||||
</div>
|
||||
<div v-else class="_panel">
|
||||
<MkNote v-for="note of user.pinnedNotes" :key="note.id" class="note" :class="$style.pinnedNote" :note="note" :pinned="true"/>
|
||||
</div>
|
||||
</div>
|
||||
<MkNotes v-else :class="$style.tl" :noGap="true" :pagination="AllPagination"/>
|
||||
</MkLazy>
|
||||
</MkStickyContainer>
|
||||
</div>
|
||||
|
@ -199,6 +209,7 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
|
|||
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
|
||||
import { useRouter } from '@/router/supplier.js';
|
||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
|
||||
const MkNote = defineAsyncComponent(() =>
|
||||
(defaultStore.state.noteDesign === 'misskey') ? import('@/components/MkNote.vue') :
|
||||
|
@ -809,7 +820,7 @@ onUnmounted(() => {
|
|||
}
|
||||
|
||||
.tab {
|
||||
margin: calc(var(--margin) / 2) 0;
|
||||
margin-bottom: calc(var(--margin) / 2);
|
||||
padding: calc(var(--margin) / 2) 0;
|
||||
background: color-mix(in srgb, var(--bg) 65%, transparent);
|
||||
backdrop-filter: var(--blur, blur(15px));
|
||||
|
@ -826,4 +837,8 @@ onUnmounted(() => {
|
|||
margin-left: 4px;
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.pinnedNote:not(:last-child) {
|
||||
border-bottom: solid 0.5px var(--divider);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -29,8 +29,9 @@ export async function warningExternalWebsite(url: string) {
|
|||
});
|
||||
|
||||
const isTrustedByUser = defaultStore.reactiveState.trustedDomains.value.includes(domain);
|
||||
const isDisabledByUser = !defaultStore.reactiveState.warnExternalUrl.value;
|
||||
|
||||
if (!isTrustedByInstance && !isTrustedByUser) {
|
||||
if (!isTrustedByInstance && !isTrustedByUser && !isDisabledByUser) {
|
||||
const confirm = await new Promise<{ canceled: boolean }>(resolve => {
|
||||
const { dispose } = os.popup(MkUrlWarningDialog, {
|
||||
url,
|
||||
|
|
|
@ -171,6 +171,10 @@ export const defaultStore = markRaw(new Storage('base', {
|
|||
where: 'account',
|
||||
default: [] as string[],
|
||||
},
|
||||
warnExternalUrl: {
|
||||
where: 'account',
|
||||
default: true,
|
||||
},
|
||||
|
||||
menu: {
|
||||
where: 'deviceAccount',
|
||||
|
|
Loading…
Reference in a new issue