mirror of
https://activitypub.software/TransFem-org/Sharkey
synced 2024-12-22 08:20:10 +00:00
merge: Minor issue fixes on the frontend (!625)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/625 Closes #659, #656, #651, #661, #632, and #710 Approved-by: dakkar <dakkar@thenautilus.net> Approved-by: fEmber <acomputerdog@gmail.com>
This commit is contained in:
commit
e2beec33f8
17 changed files with 78 additions and 26 deletions
|
@ -291,6 +291,7 @@ removeAreYouSure: "Are you sure that you want to remove \"{x}\"?"
|
|||
deleteAreYouSure: "Are you sure that you want to delete \"{x}\"?"
|
||||
resetAreYouSure: "Really reset?"
|
||||
areYouSure: "Are you sure?"
|
||||
confirmRemoteUrl: "Are you sure that you want to go to \"{x}\"?"
|
||||
saved: "Saved"
|
||||
messaging: "Chat"
|
||||
upload: "Upload"
|
||||
|
|
4
locales/index.d.ts
vendored
4
locales/index.d.ts
vendored
|
@ -1180,6 +1180,10 @@ export interface Locale extends ILocale {
|
|||
* よろしいですか?
|
||||
*/
|
||||
"areYouSure": string;
|
||||
/**
|
||||
* 「{x}」を開きますか?
|
||||
*/
|
||||
"confirmRemoteUrl": ParameterizedString<"x">;
|
||||
/**
|
||||
* 保存しました
|
||||
*/
|
||||
|
|
|
@ -291,6 +291,7 @@ removeAreYouSure: "「{x}」を削除しますか?"
|
|||
deleteAreYouSure: "「{x}」を削除しますか?"
|
||||
resetAreYouSure: "リセットしますか?"
|
||||
areYouSure: "よろしいですか?"
|
||||
confirmRemoteUrl: "「{x}」を開きますか?"
|
||||
saved: "保存しました"
|
||||
messaging: "チャット"
|
||||
upload: "アップロード"
|
||||
|
|
|
@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkLoading v-else-if="type === 'waiting'" :class="$style.iconInner" :em="true"/>
|
||||
</div>
|
||||
<header v-if="title" :class="$style.title"><Mfm :text="title"/></header>
|
||||
<div v-if="text" :class="$style.text"><Mfm :text="text" :isBlock="true" /></div>
|
||||
<div v-if="text" :class="$style.text"><Mfm :text="text" :isBlock="true" :plain="plain" /></div>
|
||||
<MkInput v-if="input" v-model="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder || undefined" :autocomplete="input.autocomplete" @keydown="onInputKeydown">
|
||||
<template v-if="input.type === 'password'" #prefix><i class="ti ti-lock"></i></template>
|
||||
<template #caption>
|
||||
|
@ -105,6 +105,7 @@ const props = withDefaults(defineProps<{
|
|||
cancelableByBgClick?: boolean;
|
||||
okText?: string;
|
||||
cancelText?: string;
|
||||
plain?: boolean;
|
||||
}>(), {
|
||||
type: 'info',
|
||||
showOkButton: true,
|
||||
|
|
|
@ -8,6 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
:is="self ? 'MkA' : 'a'" ref="el" style="word-break: break-all;" class="_link" :[attr]="self ? url.substring(local.length) : url" :rel="rel ?? 'nofollow noopener'" :target="target"
|
||||
:behavior="props.navigationBehavior"
|
||||
:title="url"
|
||||
@click.prevent="self ? true : promptConfirm()"
|
||||
@click.stop
|
||||
>
|
||||
<slot></slot>
|
||||
|
@ -22,6 +23,7 @@ import { useTooltip } from '@/scripts/use-tooltip.js';
|
|||
import * as os from '@/os.js';
|
||||
import { isEnabledUrlPreview } from '@/instance.js';
|
||||
import { MkABehavior } from '@/components/global/MkA.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
url: string;
|
||||
|
@ -47,6 +49,16 @@ if (isEnabledUrlPreview.value) {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function promptConfirm() {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'question',
|
||||
text: i18n.tsx.confirmRemoteUrl({ x: props.url }),
|
||||
plain: true,
|
||||
});
|
||||
if (canceled) return;
|
||||
window.open(props.url, '_blank', 'nofollow noopener popup=false');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
|
|
@ -5,12 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<template>
|
||||
<div :class="$style.root">
|
||||
<div v-if="media.isSensitive && hide" :class="$style.sensitive" @click="show">
|
||||
<MkMediaAudio v-if="media.type.startsWith('audio') && media.type !== 'audio/midi'" :audio="media"/>
|
||||
<div v-else-if="media.isSensitive && hide" :class="$style.sensitive" @click="show">
|
||||
<span style="font-size: 1.6em;"><i class="ti ti-alert-triangle"></i></span>
|
||||
<b>{{ i18n.ts.sensitive }}</b>
|
||||
<span>{{ i18n.ts.clickToShow }}</span>
|
||||
</div>
|
||||
<MkMediaAudio v-else-if="media.type.startsWith('audio') && media.type !== 'audio/midi'" :audio="media"/>
|
||||
<a
|
||||
v-else :class="$style.download"
|
||||
:href="media.url"
|
||||
|
|
|
@ -565,7 +565,8 @@ function quote() {
|
|||
os.post({
|
||||
renote: appearNote.value,
|
||||
channel: appearNote.value.channel,
|
||||
}).then(() => {
|
||||
}).then((cancelled) => {
|
||||
if (cancelled) return;
|
||||
misskeyApi('notes/renotes', {
|
||||
noteId: appearNote.value.id,
|
||||
userId: $i?.id,
|
||||
|
@ -589,7 +590,8 @@ function quote() {
|
|||
} else {
|
||||
os.post({
|
||||
renote: appearNote.value,
|
||||
}).then(() => {
|
||||
}).then((cancelled) => {
|
||||
if (cancelled) return;
|
||||
misskeyApi('notes/renotes', {
|
||||
noteId: appearNote.value.id,
|
||||
userId: $i?.id,
|
||||
|
|
|
@ -550,7 +550,8 @@ function quote() {
|
|||
os.post({
|
||||
renote: appearNote.value,
|
||||
channel: appearNote.value.channel,
|
||||
}).then(() => {
|
||||
}).then((cancelled) => {
|
||||
if (cancelled) return;
|
||||
misskeyApi('notes/renotes', {
|
||||
noteId: appearNote.value.id,
|
||||
userId: $i?.id,
|
||||
|
@ -574,7 +575,8 @@ function quote() {
|
|||
} else {
|
||||
os.post({
|
||||
renote: appearNote.value,
|
||||
}).then(() => {
|
||||
}).then((cancelled) => {
|
||||
if (cancelled) return;
|
||||
misskeyApi('notes/renotes', {
|
||||
noteId: appearNote.value.id,
|
||||
userId: $i?.id,
|
||||
|
|
|
@ -339,7 +339,8 @@ function quote() {
|
|||
os.post({
|
||||
renote: appearNote.value,
|
||||
channel: appearNote.value.channel,
|
||||
}).then(() => {
|
||||
}).then((cancelled) => {
|
||||
if (cancelled) return;
|
||||
misskeyApi('notes/renotes', {
|
||||
noteId: props.note.id,
|
||||
userId: $i.id,
|
||||
|
@ -363,7 +364,8 @@ function quote() {
|
|||
} else {
|
||||
os.post({
|
||||
renote: appearNote.value,
|
||||
}).then(() => {
|
||||
}).then((cancelled) => {
|
||||
if (cancelled) return;
|
||||
misskeyApi('notes/renotes', {
|
||||
noteId: props.note.id,
|
||||
userId: $i.id,
|
||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<template>
|
||||
<MkModal ref="modal" :preferType="'dialog'" @click="modal?.close()" @closed="onModalClosed()" @esc="modal?.close()">
|
||||
<MkPostForm ref="form" :class="$style.form" v-bind="props" autofocus freezeAfterPosted @posted="onPosted" @cancel="modal?.close()" @esc="modal?.close()"/>
|
||||
<MkPostForm ref="form" :class="$style.form" v-bind="props" autofocus freezeAfterPosted @posted="onPosted" @cancel="onCancel" @esc="onCancel"/>
|
||||
</MkModal>
|
||||
</template>
|
||||
|
||||
|
@ -37,7 +37,7 @@ const props = withDefaults(defineProps<{
|
|||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'closed'): void;
|
||||
(ev: 'closed', cancelled: boolean): void;
|
||||
}>();
|
||||
|
||||
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||
|
@ -47,10 +47,18 @@ function onPosted() {
|
|||
modal.value?.close({
|
||||
useSendAnimation: true,
|
||||
});
|
||||
emit('closed', false);
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
// for some reason onModalClosed does not get called properly when closing the model through other functions.
|
||||
modal.value?.close();
|
||||
// emit is required so that the dialog gets properly disposed otherwise it will float around as a "zombie"
|
||||
emit('closed', true);
|
||||
}
|
||||
|
||||
function onModalClosed() {
|
||||
emit('closed');
|
||||
emit('closed', true);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -565,7 +565,8 @@ function quote() {
|
|||
os.post({
|
||||
renote: appearNote.value,
|
||||
channel: appearNote.value.channel,
|
||||
}).then(() => {
|
||||
}).then((cancelled) => {
|
||||
if (cancelled) return;
|
||||
misskeyApi('notes/renotes', {
|
||||
noteId: appearNote.value.id,
|
||||
userId: $i?.id,
|
||||
|
@ -589,7 +590,8 @@ function quote() {
|
|||
} else {
|
||||
os.post({
|
||||
renote: appearNote.value,
|
||||
}).then(() => {
|
||||
}).then((cancelled) => {
|
||||
if (cancelled) return;
|
||||
misskeyApi('notes/renotes', {
|
||||
noteId: appearNote.value.id,
|
||||
userId: $i?.id,
|
||||
|
|
|
@ -559,7 +559,8 @@ function quote() {
|
|||
os.post({
|
||||
renote: appearNote.value,
|
||||
channel: appearNote.value.channel,
|
||||
}).then(() => {
|
||||
}).then((cancelled) => {
|
||||
if (cancelled) return;
|
||||
misskeyApi('notes/renotes', {
|
||||
noteId: appearNote.value.id,
|
||||
userId: $i?.id,
|
||||
|
@ -583,7 +584,8 @@ function quote() {
|
|||
} else {
|
||||
os.post({
|
||||
renote: appearNote.value,
|
||||
}).then(() => {
|
||||
}).then((cancelled) => {
|
||||
if (cancelled) return;
|
||||
misskeyApi('notes/renotes', {
|
||||
noteId: appearNote.value.id,
|
||||
userId: $i?.id,
|
||||
|
|
|
@ -353,7 +353,8 @@ function quote() {
|
|||
os.post({
|
||||
renote: appearNote.value,
|
||||
channel: appearNote.value.channel,
|
||||
}).then(() => {
|
||||
}).then((cancelled) => {
|
||||
if (cancelled) return;
|
||||
misskeyApi('notes/renotes', {
|
||||
noteId: props.note.id,
|
||||
userId: $i.id,
|
||||
|
@ -377,7 +378,8 @@ function quote() {
|
|||
} else {
|
||||
os.post({
|
||||
renote: appearNote.value,
|
||||
}).then(() => {
|
||||
}).then((cancelled) => {
|
||||
if (cancelled) return;
|
||||
misskeyApi('notes/renotes', {
|
||||
noteId: props.note.id,
|
||||
userId: $i.id,
|
||||
|
|
|
@ -245,6 +245,7 @@ export function confirm(props: {
|
|||
text?: string;
|
||||
okText?: string;
|
||||
cancelText?: string;
|
||||
plain?: boolean;
|
||||
}): Promise<{ canceled: boolean }> {
|
||||
return new Promise(resolve => {
|
||||
const { dispose } = popup(MkDialog, {
|
||||
|
@ -691,7 +692,7 @@ export function contextMenu(items: MenuItem[], ev: MouseEvent): Promise<void> {
|
|||
}));
|
||||
}
|
||||
|
||||
export function post(props: Record<string, any> = {}): Promise<void> {
|
||||
export function post(props: Record<string, any> = {}): Promise<void | boolean> {
|
||||
pleaseLogin(undefined, (props.initialText || props.initialNote ? {
|
||||
type: 'share',
|
||||
params: {
|
||||
|
@ -709,8 +710,8 @@ export function post(props: Record<string, any> = {}): Promise<void> {
|
|||
// 複数のpost formを開いたときに場合によってはエラーになる
|
||||
// もちろん複数のpost formを開けること自体Misskeyサイドのバグなのだが
|
||||
const { dispose } = popup(MkPostFormDialog, props, {
|
||||
closed: () => {
|
||||
resolve();
|
||||
closed: (cancelled) => {
|
||||
resolve(cancelled);
|
||||
dispose();
|
||||
},
|
||||
});
|
||||
|
|
|
@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkKeyValue>
|
||||
</button>
|
||||
<button class="_button" :class="$style.kvEditBtn" @click="describe()">
|
||||
<MkKeyValue>
|
||||
<MkKeyValue :class="$style.multiline">
|
||||
<template #key>{{ i18n.ts.description }}</template>
|
||||
<template #value>{{ file.comment ? file.comment : `(${i18n.ts.none})` }}<i class="ti ti-pencil" :class="$style.kvEditIcon"></i></template>
|
||||
</MkKeyValue>
|
||||
|
@ -313,6 +313,10 @@ onMounted(async () => {
|
|||
padding: .5rem 1rem;
|
||||
}
|
||||
|
||||
.multiline {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.kvEditBtn {
|
||||
text-align: start;
|
||||
display: block;
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
import { ref } from 'vue';
|
||||
import { Interpreter, Parser, utils, values } from '@syuilo/aiscript';
|
||||
import { aiScriptReadline, createAiScriptEnv } from '@/scripts/aiscript/api.js';
|
||||
import { inputText } from '@/os.js';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { Plugin, noteActions, notePostInterruptors, noteViewInterruptors, postFormActions, userActions, pageViewInterruptors } from '@/store.js';
|
||||
|
||||
const parser = new Parser();
|
||||
|
@ -91,8 +92,16 @@ function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Record<s
|
|||
registerPageViewInterruptor({ pluginId: opts.plugin.id, handler });
|
||||
}),
|
||||
'Plugin:open_url': values.FN_NATIVE(([url]) => {
|
||||
utils.assertString(url);
|
||||
window.open(url.value, '_blank', 'noopener');
|
||||
(async () => {
|
||||
utils.assertString(url);
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'question',
|
||||
text: i18n.tsx.confirmRemoteUrl({ x: url.value }),
|
||||
plain: true,
|
||||
});
|
||||
if (canceled) return;
|
||||
window.open(url.value, '_blank', 'noopener');
|
||||
})();
|
||||
}),
|
||||
'Plugin:config': values.OBJ(config),
|
||||
};
|
||||
|
|
|
@ -166,7 +166,6 @@ watch(defaultStore.reactiveState.menuDisplay, () => {
|
|||
top: 0;
|
||||
z-index: 1;
|
||||
padding: 16px 0;
|
||||
background: var(--bg);
|
||||
|
||||
> .button {
|
||||
min-width: 0;
|
||||
|
|
Loading…
Reference in a new issue