1
1
mirror of https://github.com/kokonect-link/cherrypick synced 2025-01-21 09:14:13 +09:00

add dedicated dialog

This commit is contained in:
kakkokari-gtyih 2024-03-22 17:03:16 +09:00
parent bf37e95e57
commit e6e119c9da
4 changed files with 160 additions and 0 deletions

15
locales/index.d.ts vendored
View File

@ -9842,6 +9842,21 @@ export interface Locale extends ILocale {
*/
"summaryProxyDescription2": string;
};
"_urlWarning": {
/**
*
*/
"title": string;
/**
*
*
*/
"description": string;
/**
* {domain}
*/
"trustThisDomain": ParameterizedString<"domain">;
};
}
declare const locales: {
[lang: string]: Locale;

View File

@ -2621,3 +2621,8 @@ _urlPreviewSetting:
summaryProxy: "プレビューを生成するプロキシのエンドポイント"
summaryProxyDescription: "Misskey本体ではなく、サマリープロキシを使用してプレビューを生成します。"
summaryProxyDescription2: "プロキシには下記パラメータがクエリ文字列として連携されます。プロキシ側がこれらをサポートしない場合、設定値は無視されます。"
_urlWarning:
title: "外部サイトに移動します"
description: "別のサイトに移動しようとしています。\nリンク先の安全性を十分に確認した上で進んでください。"
trustThisDomain: "今後{domain}のリンクを信頼する"

View File

@ -0,0 +1,136 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<MkModal ref="modal" :preferType="'dialog'" :zPriority="'high'" @click="done(true)" @closed="emit('closed')">
<div :class="$style.root" class="_gaps">
<div class="_gaps_s">
<div :class="$style.icon">
<i :class="$style.iconInner" class="ti ti-alert-triangle"></i>
</div>
<header :class="$style.title">{{ i18n.ts._urlWarning.title }}</header>
<div><Mfm :text="i18n.ts._urlWarning.description"/></div>
<div class="_monospace" :class="$style.urlAddress">{{ url }}</div>
<div>
<MkSwitch v-model="trustThisDomain">{{ i18n.tsx._urlWarning.trustThisDomain({ domain }) }}</MkSwitch>
</div>
</div>
<div :class="$style.buttons">
<MkButton data-cy-modal-dialog-ok inline primary rounded @click="ok">{{ i18n.ts.ok }}</MkButton>
<MkButton data-cy-modal-dialog-cancel inline rounded @click="cancel">{{ i18n.ts.cancel }}</MkButton>
</div>
</div>
</MkModal>
</template>
<script lang="ts" setup>
import { onBeforeUnmount, onMounted, ref, shallowRef, computed } from 'vue';
import MkModal from '@/components/MkModal.vue';
import MkButton from '@/components/MkButton.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import { i18n } from '@/i18n.js';
import { defaultStore } from '@/store.js';
type Result = string | number | true | null;
const props = withDefaults(defineProps<{
url: string;
openInNewTab?: boolean;
}>(), {
openInNewTab: true,
});
const emit = defineEmits<{
(ev: 'done', v: { canceled: true } | { canceled: false, result: Result }): void;
(ev: 'closed'): void;
}>();
const modal = shallowRef<InstanceType<typeof MkModal>>();
const trustThisDomain = ref(false);
const domain = computed(() => new URL(props.url).hostname);
// overload function 使 lint
function done(canceled: true): void;
function done(canceled: false, result: Result): void; // eslint-disable-line no-redeclare
function done(canceled: boolean, result?: Result): void { // eslint-disable-line no-redeclare
emit('done', { canceled, result } as { canceled: true } | { canceled: false, result: Result });
modal.value?.close();
}
async function ok() {
const result = true;
if (!defaultStore.state.trustedDomains.includes(domain.value) && trustThisDomain.value) {
await defaultStore.set('trustedDomains', defaultStore.state.trustedDomains.concat(domain.value));
}
done(false, result);
}
function cancel() {
done(true);
}
/*
function onBgClick() {
if (props.cancelableByBgClick) cancel();
}
*/
function onKeydown(evt: KeyboardEvent) {
if (evt.key === 'Escape') cancel();
}
onMounted(() => {
document.addEventListener('keydown', onKeydown);
});
onBeforeUnmount(() => {
document.removeEventListener('keydown', onKeydown);
});
</script>
<style lang="scss" module>
.root {
position: relative;
margin: auto;
padding: 32px;
width: 100%;
min-width: 320px;
max-width: 480px;
box-sizing: border-box;
text-align: center;
background: var(--panel);
border-radius: 16px;
}
.icon {
font-size: 24px;
color: var(--warn);
}
.iconInner {
display: block;
margin: 0 auto;
}
.title {
font-weight: bold;
font-size: 1.1em;
}
.urlAddress {
padding: 8px;
border-radius: calc(var(--radius) / 2);
border: 1px solid var(--divider);
overflow-x: auto;
white-space: nowrap;
}
.buttons {
display: flex;
gap: 8px;
flex-wrap: wrap;
justify-content: center;
}
</style>

View File

@ -132,6 +132,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'account',
default: [] as string[],
},
trustedDomains: {
where: 'account',
default: [] as string[],
},
menu: {
where: 'deviceAccount',