Merge branch 'develop' into fix-msg-room

This commit is contained in:
tamaina 2022-01-28 15:42:25 +09:00
commit 7af5562b5a
94 changed files with 750 additions and 775 deletions

View File

@ -15,6 +15,8 @@
- 投稿のNSFW画像を表示したあとにリアクションが更新されると画像が非表示になる問題を修正 - 投稿のNSFW画像を表示したあとにリアクションが更新されると画像が非表示になる問題を修正
- 「クリップ」ページが開かない問題を修正 - 「クリップ」ページが開かない問題を修正
- トレンドウィジェットが動作しないのを修正 - トレンドウィジェットが動作しないのを修正
- リアクション設定で絵文字ピッカーが開かないのを修正
- DMページでメンションが含まれる問題を修正
## 12.102.1 (2022/01/27) ## 12.102.1 (2022/01/27)
### Bugfixes ### Bugfixes

View File

@ -192,31 +192,31 @@ export async function openAccountMenu(opts: {
if (opts.withExtraOperation) { if (opts.withExtraOperation) {
popupMenu([...[{ popupMenu([...[{
type: 'link', type: 'link',
text: i18n.locale.profile, text: i18n.ts.profile,
to: `/@${ $i.username }`, to: `/@${ $i.username }`,
avatar: $i, avatar: $i,
}, null, ...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises, { }, null, ...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises, {
icon: 'fas fa-plus', icon: 'fas fa-plus',
text: i18n.locale.addAccount, text: i18n.ts.addAccount,
action: () => { action: () => {
popupMenu([{ popupMenu([{
text: i18n.locale.existingAccount, text: i18n.ts.existingAccount,
action: () => { showSigninDialog(); }, action: () => { showSigninDialog(); },
}, { }, {
text: i18n.locale.createAccount, text: i18n.ts.createAccount,
action: () => { createAccount(); }, action: () => { createAccount(); },
}], ev.currentTarget || ev.target); }], ev.currentTarget ?? ev.target);
}, },
}, { }, {
type: 'link', type: 'link',
icon: 'fas fa-users', icon: 'fas fa-users',
text: i18n.locale.manageAccounts, text: i18n.ts.manageAccounts,
to: `/settings/accounts`, to: `/settings/accounts`,
}]], ev.currentTarget || ev.target, { }]], ev.currentTarget ?? ev.target, {
align: 'left' align: 'left'
}); });
} else { } else {
popupMenu([...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises], ev.currentTarget || ev.target, { popupMenu([...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises], ev.currentTarget ?? ev.target, {
align: 'left' align: 'left'
}); });
} }

View File

@ -2,7 +2,7 @@
<XWindow ref="window" :initial-width="400" :initial-height="500" :can-resize="true" @closed="emit('closed')"> <XWindow ref="window" :initial-width="400" :initial-height="500" :can-resize="true" @closed="emit('closed')">
<template #header> <template #header>
<i class="fas fa-exclamation-circle" style="margin-right: 0.5em;"></i> <i class="fas fa-exclamation-circle" style="margin-right: 0.5em;"></i>
<I18n :src="i18n.locale.reportAbuseOf" tag="span"> <I18n :src="i18n.ts.reportAbuseOf" tag="span">
<template #name> <template #name>
<b><MkAcct :user="user"/></b> <b><MkAcct :user="user"/></b>
</template> </template>
@ -11,12 +11,12 @@
<div class="dpvffvvy _monolithic_"> <div class="dpvffvvy _monolithic_">
<div class="_section"> <div class="_section">
<MkTextarea v-model="comment"> <MkTextarea v-model="comment">
<template #label>{{ i18n.locale.details }}</template> <template #label>{{ i18n.ts.details }}</template>
<template #caption>{{ i18n.locale.fillAbuseReportDescription }}</template> <template #caption>{{ i18n.ts.fillAbuseReportDescription }}</template>
</MkTextarea> </MkTextarea>
</div> </div>
<div class="_section"> <div class="_section">
<MkButton primary full :disabled="comment.length === 0" @click="send">{{ i18n.locale.send }}</MkButton> <MkButton primary full :disabled="comment.length === 0" @click="send">{{ i18n.ts.send }}</MkButton>
</div> </div>
</div> </div>
</XWindow> </XWindow>
@ -50,7 +50,7 @@ function send() {
}, undefined).then(res => { }, undefined).then(res => {
os.alert({ os.alert({
type: 'success', type: 'success',
text: i18n.locale.abuseReported text: i18n.ts.abuseReported
}); });
window.value?.close(); window.value?.close();
emit('closed'); emit('closed');

View File

@ -8,7 +8,7 @@
</span> </span>
<span class="username">@{{ acct(user) }}</span> <span class="username">@{{ acct(user) }}</span>
</li> </li>
<li tabindex="-1" class="choose" @click="chooseUser()" @keydown="onKeydown">{{ i18n.locale.selectUser }}</li> <li tabindex="-1" class="choose" @click="chooseUser()" @keydown="onKeydown">{{ i18n.ts.selectUser }}</li>
</ol> </ol>
<ol v-else-if="hashtags.length > 0" ref="suggests" class="hashtags"> <ol v-else-if="hashtags.length > 0" ref="suggests" class="hashtags">
<li v-for="hashtag in hashtags" tabindex="-1" @click="complete(type, hashtag)" @keydown="onKeydown"> <li v-for="hashtag in hashtags" tabindex="-1" @click="complete(type, hashtag)" @keydown="onKeydown">

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<span v-if="!available">{{ i18n.locale.waiting }}<MkEllipsis/></span> <span v-if="!available">{{ i18n.ts.waiting }}<MkEllipsis/></span>
<div ref="captchaEl"></div> <div ref="captchaEl"></div>
</div> </div>
</template> </template>

View File

@ -6,14 +6,14 @@
> >
<template v-if="!wait"> <template v-if="!wait">
<template v-if="isFollowing"> <template v-if="isFollowing">
<span v-if="full">{{ i18n.locale.unfollow }}</span><i class="fas fa-minus"></i> <span v-if="full">{{ i18n.ts.unfollow }}</span><i class="fas fa-minus"></i>
</template> </template>
<template v-else> <template v-else>
<span v-if="full">{{ i18n.locale.follow }}</span><i class="fas fa-plus"></i> <span v-if="full">{{ i18n.ts.follow }}</span><i class="fas fa-plus"></i>
</template> </template>
</template> </template>
<template v-else> <template v-else>
<span v-if="full">{{ i18n.locale.processing }}</span><i class="fas fa-spinner fa-pulse fa-fw"></i> <span v-if="full">{{ i18n.ts.processing }}</span><i class="fas fa-spinner fa-pulse fa-fw"></i>
</template> </template>
</button> </button>
</template> </template>

View File

@ -6,7 +6,7 @@
<div class="status"> <div class="status">
<div> <div>
<i class="fas fa-users fa-fw"></i> <i class="fas fa-users fa-fw"></i>
<I18n :src="i18n.locale._channel.usersCount" tag="span" style="margin-left: 4px;"> <I18n :src="i18n.ts._channel.usersCount" tag="span" style="margin-left: 4px;">
<template #n> <template #n>
<b>{{ channel.usersCount }}</b> <b>{{ channel.usersCount }}</b>
</template> </template>
@ -14,7 +14,7 @@
</div> </div>
<div> <div>
<i class="fas fa-pencil-alt fa-fw"></i> <i class="fas fa-pencil-alt fa-fw"></i>
<I18n :src="i18n.locale._channel.notesCount" tag="span" style="margin-left: 4px;"> <I18n :src="i18n.ts._channel.notesCount" tag="span" style="margin-left: 4px;">
<template #n> <template #n>
<b>{{ channel.notesCount }}</b> <b>{{ channel.notesCount }}</b>
</template> </template>
@ -27,7 +27,7 @@
</article> </article>
<footer> <footer>
<span v-if="channel.lastNotedAt"> <span v-if="channel.lastNotedAt">
{{ i18n.locale.updatedAt }}: <MkTime :time="channel.lastNotedAt"/> {{ i18n.ts.updatedAt }}: <MkTime :time="channel.lastNotedAt"/>
</span> </span>
</footer> </footer>
</MkA> </MkA>

View File

@ -143,6 +143,7 @@ export default defineComponent({
} }
const gridColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'; const gridColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
// //
Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--fg'); Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--fg');
@ -255,6 +256,27 @@ export default defineComponent({
}, },
}, },
}, },
plugins: [{
id: 'vLine',
beforeDraw(chart, args, options) {
if (chart.tooltip._active && chart.tooltip._active.length) {
const activePoint = chart.tooltip._active[0];
const ctx = chart.ctx;
const x = activePoint.element.x;
const topY = chart.scales.y.top;
const bottomY = chart.scales.y.bottom;
ctx.save();
ctx.beginPath();
ctx.moveTo(x, bottomY);
ctx.lineTo(x, topY);
ctx.lineWidth = 1;
ctx.strokeStyle = vLineColor;
ctx.stroke();
ctx.restore();
}
}
}]
}); });
}; };

View File

@ -1,6 +1,6 @@
<template> <template>
<button class="nrvgflfu _button" @click="toggle"> <button class="nrvgflfu _button" @click="toggle">
<b>{{ modelValue ? i18n.locale._cw.hide : i18n.locale._cw.show }}</b> <b>{{ modelValue ? i18n.ts._cw.hide : i18n.ts._cw.show }}</b>
<span v-if="!modelValue">{{ label }}</span> <span v-if="!modelValue">{{ label }}</span>
</button> </button>
</template> </template>
@ -25,7 +25,7 @@ const label = computed(() => {
return concat([ return concat([
props.note.text ? [i18n.t('_cw.chars', { count: length(props.note.text) })] : [], props.note.text ? [i18n.t('_cw.chars', { count: length(props.note.text) })] : [],
props.note.files && props.note.files.length !== 0 ? [i18n.t('_cw.files', { count: props.note.files.length }) ] : [], props.note.files && props.note.files.length !== 0 ? [i18n.t('_cw.files', { count: props.note.files.length }) ] : [],
props.note.poll != null ? [i18n.locale.poll] : [] props.note.poll != null ? [i18n.ts.poll] : []
] as string[][]).join(' / '); ] as string[][]).join(' / ');
}); });

View File

@ -28,8 +28,8 @@
</template> </template>
</MkSelect> </MkSelect>
<div v-if="(showOkButton || showCancelButton) && !actions" class="buttons"> <div v-if="(showOkButton || showCancelButton) && !actions" class="buttons">
<MkButton v-if="showOkButton" inline primary :autofocus="!input && !select" @click="ok">{{ (showCancelButton || input || select) ? i18n.locale.ok : i18n.locale.gotIt }}</MkButton> <MkButton v-if="showOkButton" inline primary :autofocus="!input && !select" @click="ok">{{ (showCancelButton || input || select) ? i18n.ts.ok : i18n.ts.gotIt }}</MkButton>
<MkButton v-if="showCancelButton || input || select" inline @click="cancel">{{ i18n.locale.cancel }}</MkButton> <MkButton v-if="showCancelButton || input || select" inline @click="cancel">{{ i18n.ts.cancel }}</MkButton>
</div> </div>
<div v-if="actions" class="buttons"> <div v-if="actions" class="buttons">
<MkButton v-for="action in actions" :key="action.text" inline :primary="action.primary" @click="() => { action.callback(); close(); }">{{ action.text }}</MkButton> <MkButton v-for="action in actions" :key="action.text" inline :primary="action.primary" @click="() => { action.callback(); close(); }">{{ action.text }}</MkButton>

View File

@ -10,7 +10,7 @@
@closed="emit('closed')" @closed="emit('closed')"
> >
<template #header> <template #header>
{{ multiple ? ((type === 'file') ? i18n.locale.selectFiles : i18n.locale.selectFolders) : ((type === 'file') ? i18n.locale.selectFile : i18n.locale.selectFolder) }} {{ multiple ? ((type === 'file') ? i18n.ts.selectFiles : i18n.ts.selectFolders) : ((type === 'file') ? i18n.ts.selectFile : i18n.ts.selectFolder) }}
<span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ number(selected.length) }})</span> <span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ number(selected.length) }})</span>
</template> </template>
<XDrive :multiple="multiple" :select="type" @changeSelection="onChangeSelection" @selected="ok()"/> <XDrive :multiple="multiple" :select="type" @changeSelection="onChangeSelection" @selected="ok()"/>

View File

@ -6,7 +6,7 @@
@closed="emit('closed')" @closed="emit('closed')"
> >
<template #header> <template #header>
{{ i18n.locale.drive }} {{ i18n.ts.drive }}
</template> </template>
<XDrive :initial-folder="initialFolder"/> <XDrive :initial-folder="initialFolder"/>
</XWindow> </XWindow>

View File

@ -10,15 +10,15 @@
> >
<div v-if="$i?.avatarId == file.id" class="label"> <div v-if="$i?.avatarId == file.id" class="label">
<img src="/client-assets/label.svg"/> <img src="/client-assets/label.svg"/>
<p>{{ i18n.locale.avatar }}</p> <p>{{ i18n.ts.avatar }}</p>
</div> </div>
<div v-if="$i?.bannerId == file.id" class="label"> <div v-if="$i?.bannerId == file.id" class="label">
<img src="/client-assets/label.svg"/> <img src="/client-assets/label.svg"/>
<p>{{ i18n.locale.banner }}</p> <p>{{ i18n.ts.banner }}</p>
</div> </div>
<div v-if="file.isSensitive" class="label red"> <div v-if="file.isSensitive" class="label red">
<img src="/client-assets/label-red.svg"/> <img src="/client-assets/label-red.svg"/>
<p>{{ i18n.locale.nsfw }}</p> <p>{{ i18n.ts.nsfw }}</p>
</div> </div>
<MkDriveFileThumbnail class="thumbnail" :file="file" fit="contain"/> <MkDriveFileThumbnail class="thumbnail" :file="file" fit="contain"/>
@ -61,30 +61,30 @@ const title = computed(() => `${props.file.name}\n${props.file.type} ${bytes(pro
function getMenu() { function getMenu() {
return [{ return [{
text: i18n.locale.rename, text: i18n.ts.rename,
icon: 'fas fa-i-cursor', icon: 'fas fa-i-cursor',
action: rename action: rename
}, { }, {
text: props.file.isSensitive ? i18n.locale.unmarkAsSensitive : i18n.locale.markAsSensitive, text: props.file.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive,
icon: props.file.isSensitive ? 'fas fa-eye' : 'fas fa-eye-slash', icon: props.file.isSensitive ? 'fas fa-eye' : 'fas fa-eye-slash',
action: toggleSensitive action: toggleSensitive
}, { }, {
text: i18n.locale.describeFile, text: i18n.ts.describeFile,
icon: 'fas fa-i-cursor', icon: 'fas fa-i-cursor',
action: describe action: describe
}, null, { }, null, {
text: i18n.locale.copyUrl, text: i18n.ts.copyUrl,
icon: 'fas fa-link', icon: 'fas fa-link',
action: copyUrl action: copyUrl
}, { }, {
type: 'a', type: 'a',
href: props.file.url, href: props.file.url,
target: '_blank', target: '_blank',
text: i18n.locale.download, text: i18n.ts.download,
icon: 'fas fa-download', icon: 'fas fa-download',
download: props.file.name download: props.file.name
}, null, { }, null, {
text: i18n.locale.delete, text: i18n.ts.delete,
icon: 'fas fa-trash-alt', icon: 'fas fa-trash-alt',
danger: true, danger: true,
action: deleteFile action: deleteFile
@ -95,7 +95,7 @@ function onClick(ev: MouseEvent) {
if (props.selectMode) { if (props.selectMode) {
emit('chosen', props.file); emit('chosen', props.file);
} else { } else {
os.popupMenu(getMenu(), (ev.currentTarget || ev.target || undefined) as HTMLElement | undefined); os.popupMenu(getMenu(), (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
} }
} }
@ -120,8 +120,8 @@ function onDragend() {
function rename() { function rename() {
os.inputText({ os.inputText({
title: i18n.locale.renameFile, title: i18n.ts.renameFile,
placeholder: i18n.locale.inputNewFileName, placeholder: i18n.ts.inputNewFileName,
default: props.file.name, default: props.file.name,
}).then(({ canceled, result: name }) => { }).then(({ canceled, result: name }) => {
if (canceled) return; if (canceled) return;
@ -134,9 +134,9 @@ function rename() {
function describe() { function describe() {
os.popup(import('@/components/media-caption.vue'), { os.popup(import('@/components/media-caption.vue'), {
title: i18n.locale.describeFile, title: i18n.ts.describeFile,
input: { input: {
placeholder: i18n.locale.inputNewDescription, placeholder: i18n.ts.inputNewDescription,
default: props.file.comment !== null ? props.file.comment : '', default: props.file.comment !== null ? props.file.comment : '',
}, },
image: props.file image: props.file

View File

@ -20,7 +20,7 @@
{{ folder.name }} {{ folder.name }}
</p> </p>
<p v-if="defaultStore.state.uploadFolder == folder.id" class="upload"> <p v-if="defaultStore.state.uploadFolder == folder.id" class="upload">
{{ i18n.locale.uploadFolder }} {{ i18n.ts.uploadFolder }}
</p> </p>
<button v-if="selectMode" class="checkbox _button" :class="{ checked: isSelected }" @click.prevent.stop="checkboxClicked"></button> <button v-if="selectMode" class="checkbox _button" :class="{ checked: isSelected }" @click.prevent.stop="checkboxClicked"></button>
</div> </div>
@ -146,14 +146,14 @@ function onDrop(ev: DragEvent) {
switch (err) { switch (err) {
case 'detected-circular-definition': case 'detected-circular-definition':
os.alert({ os.alert({
title: i18n.locale.unableToProcess, title: i18n.ts.unableToProcess,
text: i18n.locale.circularReferenceFolder text: i18n.ts.circularReferenceFolder
}); });
break; break;
default: default:
os.alert({ os.alert({
type: 'error', type: 'error',
text: i18n.locale.somethingHappened text: i18n.ts.somethingHappened
}); });
} }
}); });
@ -184,8 +184,8 @@ function go() {
function rename() { function rename() {
os.inputText({ os.inputText({
title: i18n.locale.renameFolder, title: i18n.ts.renameFolder,
placeholder: i18n.locale.inputNewFolderName, placeholder: i18n.ts.inputNewFolderName,
default: props.folder.name default: props.folder.name
}).then(({ canceled, result: name }) => { }).then(({ canceled, result: name }) => {
if (canceled) return; if (canceled) return;
@ -208,14 +208,14 @@ function deleteFolder() {
case 'b0fc8a17-963c-405d-bfbc-859a487295e1': case 'b0fc8a17-963c-405d-bfbc-859a487295e1':
os.alert({ os.alert({
type: 'error', type: 'error',
title: i18n.locale.unableToDelete, title: i18n.ts.unableToDelete,
text: i18n.locale.hasChildFilesOrFolders text: i18n.ts.hasChildFilesOrFolders
}); });
break; break;
default: default:
os.alert({ os.alert({
type: 'error', type: 'error',
text: i18n.locale.unableToDelete text: i18n.ts.unableToDelete
}); });
} }
}); });
@ -227,7 +227,7 @@ function setAsUploadFolder() {
function onContextmenu(ev: MouseEvent) { function onContextmenu(ev: MouseEvent) {
os.contextMenu([{ os.contextMenu([{
text: i18n.locale.openInWindow, text: i18n.ts.openInWindow,
icon: 'fas fa-window-restore', icon: 'fas fa-window-restore',
action: () => { action: () => {
os.popup(import('./drive-window.vue'), { os.popup(import('./drive-window.vue'), {
@ -236,11 +236,11 @@ function onContextmenu(ev: MouseEvent) {
}, 'closed'); }, 'closed');
} }
}, null, { }, null, {
text: i18n.locale.rename, text: i18n.ts.rename,
icon: 'fas fa-i-cursor', icon: 'fas fa-i-cursor',
action: rename, action: rename,
}, null, { }, null, {
text: i18n.locale.delete, text: i18n.ts.delete,
icon: 'fas fa-trash-alt', icon: 'fas fa-trash-alt',
danger: true, danger: true,
action: deleteFolder, action: deleteFolder,

View File

@ -8,7 +8,7 @@
@drop.stop="onDrop" @drop.stop="onDrop"
> >
<i v-if="folder == null" class="fas fa-cloud"></i> <i v-if="folder == null" class="fas fa-cloud"></i>
<span>{{ folder == null ? i18n.locale.drive : folder.name }}</span> <span>{{ folder == null ? i18n.ts.drive : folder.name }}</span>
</div> </div>
</template> </template>

View File

@ -54,7 +54,7 @@
/> />
<!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid --> <!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
<div v-for="(n, i) in 16" :key="i" class="padding"></div> <div v-for="(n, i) in 16" :key="i" class="padding"></div>
<MkButton v-if="moreFolders" ref="moreFolders">{{ i18n.locale.loadMore }}</MkButton> <MkButton v-if="moreFolders" ref="moreFolders">{{ i18n.ts.loadMore }}</MkButton>
</div> </div>
<div v-show="files.length > 0" ref="filesContainer" class="files"> <div v-show="files.length > 0" ref="filesContainer" class="files">
<XFile <XFile
@ -71,12 +71,12 @@
/> />
<!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid --> <!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
<div v-for="(n, i) in 16" :key="i" class="padding"></div> <div v-for="(n, i) in 16" :key="i" class="padding"></div>
<MkButton v-show="moreFiles" ref="loadMoreFiles" @click="fetchMoreFiles">{{ i18n.locale.loadMore }}</MkButton> <MkButton v-show="moreFiles" ref="loadMoreFiles" @click="fetchMoreFiles">{{ i18n.ts.loadMore }}</MkButton>
</div> </div>
<div v-if="files.length == 0 && folders.length == 0 && !fetching" class="empty"> <div v-if="files.length == 0 && folders.length == 0 && !fetching" class="empty">
<p v-if="draghover">{{ i18n.t('empty-draghover') }}</p> <p v-if="draghover">{{ i18n.t('empty-draghover') }}</p>
<p v-if="!draghover && folder == null"><strong>{{ i18n.locale.emptyDrive }}</strong><br/>{{ i18n.t('empty-drive-description') }}</p> <p v-if="!draghover && folder == null"><strong>{{ i18n.ts.emptyDrive }}</strong><br/>{{ i18n.t('empty-drive-description') }}</p>
<p v-if="!draghover && folder != null">{{ i18n.locale.emptyFolder }}</p> <p v-if="!draghover && folder != null">{{ i18n.ts.emptyFolder }}</p>
</div> </div>
</div> </div>
<MkLoading v-if="fetching"/> <MkLoading v-if="fetching"/>
@ -253,14 +253,14 @@ function onDrop(e: DragEvent): any {
switch (err) { switch (err) {
case 'detected-circular-definition': case 'detected-circular-definition':
os.alert({ os.alert({
title: i18n.locale.unableToProcess, title: i18n.ts.unableToProcess,
text: i18n.locale.circularReferenceFolder text: i18n.ts.circularReferenceFolder
}); });
break; break;
default: default:
os.alert({ os.alert({
type: 'error', type: 'error',
text: i18n.locale.somethingHappened text: i18n.ts.somethingHappened
}); });
} }
}); });
@ -274,9 +274,9 @@ function selectLocalFile() {
function urlUpload() { function urlUpload() {
os.inputText({ os.inputText({
title: i18n.locale.uploadFromUrl, title: i18n.ts.uploadFromUrl,
type: 'url', type: 'url',
placeholder: i18n.locale.uploadFromUrlDescription placeholder: i18n.ts.uploadFromUrlDescription
}).then(({ canceled, result: url }) => { }).then(({ canceled, result: url }) => {
if (canceled || !url) return; if (canceled || !url) return;
os.api('drive/files/upload-from-url', { os.api('drive/files/upload-from-url', {
@ -285,16 +285,16 @@ function urlUpload() {
}); });
os.alert({ os.alert({
title: i18n.locale.uploadFromUrlRequested, title: i18n.ts.uploadFromUrlRequested,
text: i18n.locale.uploadFromUrlMayTakeTime text: i18n.ts.uploadFromUrlMayTakeTime
}); });
}); });
} }
function createFolder() { function createFolder() {
os.inputText({ os.inputText({
title: i18n.locale.createFolder, title: i18n.ts.createFolder,
placeholder: i18n.locale.folderName placeholder: i18n.ts.folderName
}).then(({ canceled, result: name }) => { }).then(({ canceled, result: name }) => {
if (canceled) return; if (canceled) return;
os.api('drive/folders/create', { os.api('drive/folders/create', {
@ -308,8 +308,8 @@ function createFolder() {
function renameFolder(folderToRename: Misskey.entities.DriveFolder) { function renameFolder(folderToRename: Misskey.entities.DriveFolder) {
os.inputText({ os.inputText({
title: i18n.locale.renameFolder, title: i18n.ts.renameFolder,
placeholder: i18n.locale.inputNewFolderName, placeholder: i18n.ts.inputNewFolderName,
default: folderToRename.name default: folderToRename.name
}).then(({ canceled, result: name }) => { }).then(({ canceled, result: name }) => {
if (canceled) return; if (canceled) return;
@ -334,14 +334,14 @@ function deleteFolder(folderToDelete: Misskey.entities.DriveFolder) {
case 'b0fc8a17-963c-405d-bfbc-859a487295e1': case 'b0fc8a17-963c-405d-bfbc-859a487295e1':
os.alert({ os.alert({
type: 'error', type: 'error',
title: i18n.locale.unableToDelete, title: i18n.ts.unableToDelete,
text: i18n.locale.hasChildFilesOrFolders text: i18n.ts.hasChildFilesOrFolders
}); });
break; break;
default: default:
os.alert({ os.alert({
type: 'error', type: 'error',
text: i18n.locale.unableToDelete text: i18n.ts.unableToDelete
}); });
} }
}); });
@ -562,36 +562,36 @@ function fetchMoreFiles() {
function getMenu() { function getMenu() {
return [{ return [{
text: i18n.locale.addFile, text: i18n.ts.addFile,
type: 'label' type: 'label'
}, { }, {
text: i18n.locale.upload, text: i18n.ts.upload,
icon: 'fas fa-upload', icon: 'fas fa-upload',
action: () => { selectLocalFile(); } action: () => { selectLocalFile(); }
}, { }, {
text: i18n.locale.fromUrl, text: i18n.ts.fromUrl,
icon: 'fas fa-link', icon: 'fas fa-link',
action: () => { urlUpload(); } action: () => { urlUpload(); }
}, null, { }, null, {
text: folder.value ? folder.value.name : i18n.locale.drive, text: folder.value ? folder.value.name : i18n.ts.drive,
type: 'label' type: 'label'
}, folder.value ? { }, folder.value ? {
text: i18n.locale.renameFolder, text: i18n.ts.renameFolder,
icon: 'fas fa-i-cursor', icon: 'fas fa-i-cursor',
action: () => { renameFolder(folder.value); } action: () => { renameFolder(folder.value); }
} : undefined, folder.value ? { } : undefined, folder.value ? {
text: i18n.locale.deleteFolder, text: i18n.ts.deleteFolder,
icon: 'fas fa-trash-alt', icon: 'fas fa-trash-alt',
action: () => { deleteFolder(folder.value as Misskey.entities.DriveFolder); } action: () => { deleteFolder(folder.value as Misskey.entities.DriveFolder); }
} : undefined, { } : undefined, {
text: i18n.locale.createFolder, text: i18n.ts.createFolder,
icon: 'fas fa-folder-plus', icon: 'fas fa-folder-plus',
action: () => { createFolder(); } action: () => { createFolder(); }
}]; }];
} }
function showMenu(ev: MouseEvent) { function showMenu(ev: MouseEvent) {
os.popupMenu(getMenu(), (ev.currentTarget || ev.target || undefined) as HTMLElement | undefined); os.popupMenu(getMenu(), (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
} }
function onContextmenu(ev: MouseEvent) { function onContextmenu(ev: MouseEvent) {

View File

@ -32,20 +32,20 @@ import MkEmojiPicker from '@/components/emoji-picker.vue';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
withDefaults(defineProps<{ withDefaults(defineProps<{
manualShowing?: boolean; manualShowing?: boolean | null;
src?: HTMLElement; src?: HTMLElement;
showPinned?: boolean; showPinned?: boolean;
asReactionPicker?: boolean; asReactionPicker?: boolean;
}>(), { }>(), {
manualShowing: false, manualShowing: null,
showPinned: true, showPinned: true,
asReactionPicker: false, asReactionPicker: false,
}); });
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'done', v: any): void; (ev: 'done', v: any): void;
(e: 'close'): void; (ev: 'close'): void;
(e: 'closed'): void; (ev: 'closed'): void;
}>(); }>();
const modal = ref<InstanceType<typeof MkModal>>(); const modal = ref<InstanceType<typeof MkModal>>();

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="omfetrab" :class="['w' + width, 'h' + height, { big, asDrawer }]" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }"> <div class="omfetrab" :class="['w' + width, 'h' + height, { big, asDrawer }]" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }">
<input ref="search" v-model.trim="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="i18n.locale.search" @paste.stop="paste" @keyup.enter="done()"> <input ref="search" v-model.trim="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="i18n.ts.search" @paste.stop="paste" @keyup.enter="done()">
<div ref="emojis" class="emojis"> <div ref="emojis" class="emojis">
<section class="result"> <section class="result">
<div v-if="searchResultCustom.length > 0"> <div v-if="searchResultCustom.length > 0">
@ -43,7 +43,7 @@
</section> </section>
<section> <section>
<header class="_acrylic"><i class="far fa-clock fa-fw"></i> {{ i18n.locale.recentUsed }}</header> <header class="_acrylic"><i class="far fa-clock fa-fw"></i> {{ i18n.ts.recentUsed }}</header>
<div> <div>
<button v-for="emoji in recentlyUsedEmojis" <button v-for="emoji in recentlyUsedEmojis"
:key="emoji" :key="emoji"
@ -56,11 +56,11 @@
</section> </section>
</div> </div>
<div> <div>
<header class="_acrylic">{{ i18n.locale.customEmojis }}</header> <header class="_acrylic">{{ i18n.ts.customEmojis }}</header>
<XSection v-for="category in customEmojiCategories" :key="'custom:' + category" :initial-shown="false" :emojis="customEmojis.filter(e => e.category === category).map(e => ':' + e.name + ':')" @chosen="chosen">{{ category || i18n.locale.other }}</XSection> <XSection v-for="category in customEmojiCategories" :key="'custom:' + category" :initial-shown="false" :emojis="customEmojis.filter(e => e.category === category).map(e => ':' + e.name + ':')" @chosen="chosen">{{ category || i18n.ts.other }}</XSection>
</div> </div>
<div> <div>
<header class="_acrylic">{{ i18n.locale.emoji }}</header> <header class="_acrylic">{{ i18n.ts.emoji }}</header>
<XSection v-for="category in categories" :emojis="emojilist.filter(e => e.category === category).map(e => e.char)" @chosen="chosen">{{ category }}</XSection> <XSection v-for="category in categories" :emojis="emojilist.filter(e => e.category === category).map(e => e.char)" @chosen="chosen">{{ category }}</XSection>
</div> </div>
</div> </div>
@ -280,7 +280,7 @@ function getKey(emoji: string | Misskey.entities.CustomEmoji | UnicodeEmojiDef):
} }
function chosen(emoji: any, ev?: MouseEvent) { function chosen(emoji: any, ev?: MouseEvent) {
const el = ev && (ev.currentTarget || ev.target) as HTMLElement | null | undefined; const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined;
if (el) { if (el) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);

View File

@ -6,23 +6,23 @@
> >
<template v-if="!wait"> <template v-if="!wait">
<template v-if="hasPendingFollowRequestFromYou && user.isLocked"> <template v-if="hasPendingFollowRequestFromYou && user.isLocked">
<span v-if="full">{{ i18n.locale.followRequestPending }}</span><i class="fas fa-hourglass-half"></i> <span v-if="full">{{ i18n.ts.followRequestPending }}</span><i class="fas fa-hourglass-half"></i>
</template> </template>
<template v-else-if="hasPendingFollowRequestFromYou && !user.isLocked"> <!-- つまりリモートフォローの場合 --> <template v-else-if="hasPendingFollowRequestFromYou && !user.isLocked"> <!-- つまりリモートフォローの場合 -->
<span v-if="full">{{ i18n.locale.processing }}</span><i class="fas fa-spinner fa-pulse"></i> <span v-if="full">{{ i18n.ts.processing }}</span><i class="fas fa-spinner fa-pulse"></i>
</template> </template>
<template v-else-if="isFollowing"> <template v-else-if="isFollowing">
<span v-if="full">{{ i18n.locale.unfollow }}</span><i class="fas fa-minus"></i> <span v-if="full">{{ i18n.ts.unfollow }}</span><i class="fas fa-minus"></i>
</template> </template>
<template v-else-if="!isFollowing && user.isLocked"> <template v-else-if="!isFollowing && user.isLocked">
<span v-if="full">{{ i18n.locale.followRequest }}</span><i class="fas fa-plus"></i> <span v-if="full">{{ i18n.ts.followRequest }}</span><i class="fas fa-plus"></i>
</template> </template>
<template v-else-if="!isFollowing && !user.isLocked"> <template v-else-if="!isFollowing && !user.isLocked">
<span v-if="full">{{ i18n.locale.follow }}</span><i class="fas fa-plus"></i> <span v-if="full">{{ i18n.ts.follow }}</span><i class="fas fa-plus"></i>
</template> </template>
</template> </template>
<template v-else> <template v-else>
<span v-if="full">{{ i18n.locale.processing }}</span><i class="fas fa-spinner fa-pulse fa-fw"></i> <span v-if="full">{{ i18n.ts.processing }}</span><i class="fas fa-spinner fa-pulse fa-fw"></i>
</template> </template>
</button> </button>
</template> </template>

View File

@ -5,28 +5,28 @@
@close="dialog.close()" @close="dialog.close()"
@closed="emit('closed')" @closed="emit('closed')"
> >
<template #header>{{ i18n.locale.forgotPassword }}</template> <template #header>{{ i18n.ts.forgotPassword }}</template>
<form v-if="instance.enableEmail" class="bafeceda" @submit.prevent="onSubmit"> <form v-if="instance.enableEmail" class="bafeceda" @submit.prevent="onSubmit">
<div class="main _formRoot"> <div class="main _formRoot">
<MkInput v-model="username" class="_formBlock" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required> <MkInput v-model="username" class="_formBlock" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required>
<template #label>{{ i18n.locale.username }}</template> <template #label>{{ i18n.ts.username }}</template>
<template #prefix>@</template> <template #prefix>@</template>
</MkInput> </MkInput>
<MkInput v-model="email" class="_formBlock" type="email" spellcheck="false" required> <MkInput v-model="email" class="_formBlock" type="email" spellcheck="false" required>
<template #label>{{ i18n.locale.emailAddress }}</template> <template #label>{{ i18n.ts.emailAddress }}</template>
<template #caption>{{ i18n.locale._forgotPassword.enterEmail }}</template> <template #caption>{{ i18n.ts._forgotPassword.enterEmail }}</template>
</MkInput> </MkInput>
<MkButton class="_formBlock" type="submit" :disabled="processing" primary style="margin: 0 auto;">{{ i18n.locale.send }}</MkButton> <MkButton class="_formBlock" type="submit" :disabled="processing" primary style="margin: 0 auto;">{{ i18n.ts.send }}</MkButton>
</div> </div>
<div class="sub"> <div class="sub">
<MkA to="/about" class="_link">{{ i18n.locale._forgotPassword.ifNoEmail }}</MkA> <MkA to="/about" class="_link">{{ i18n.ts._forgotPassword.ifNoEmail }}</MkA>
</div> </div>
</form> </form>
<div v-else class="bafecedb"> <div v-else class="bafecedb">
{{ i18n.locale._forgotPassword.contactAdmin }} {{ i18n.ts._forgotPassword.contactAdmin }}
</div> </div>
</XModalWindow> </XModalWindow>
</template> </template>

View File

@ -43,31 +43,31 @@ function onContextmenu(ev) {
text: props.to, text: props.to,
}, { }, {
icon: 'fas fa-window-maximize', icon: 'fas fa-window-maximize',
text: i18n.locale.openInWindow, text: i18n.ts.openInWindow,
action: () => { action: () => {
os.pageWindow(props.to); os.pageWindow(props.to);
} }
}, sideViewHook ? { }, sideViewHook ? {
icon: 'fas fa-columns', icon: 'fas fa-columns',
text: i18n.locale.openInSideView, text: i18n.ts.openInSideView,
action: () => { action: () => {
sideViewHook(props.to); sideViewHook(props.to);
} }
} : undefined, { } : undefined, {
icon: 'fas fa-expand-alt', icon: 'fas fa-expand-alt',
text: i18n.locale.showInPage, text: i18n.ts.showInPage,
action: () => { action: () => {
router.push(props.to); router.push(props.to);
} }
}, null, { }, null, {
icon: 'fas fa-external-link-alt', icon: 'fas fa-external-link-alt',
text: i18n.locale.openInNewTab, text: i18n.ts.openInNewTab,
action: () => { action: () => {
window.open(props.to, '_blank'); window.open(props.to, '_blank');
} }
}, { }, {
icon: 'fas fa-link', icon: 'fas fa-link',
text: i18n.locale.copyLink, text: i18n.ts.copyLink,
action: () => { action: () => {
copyToClipboard(`${url}${props.to}`); copyToClipboard(`${url}${props.to}`);
} }

View File

@ -104,7 +104,7 @@ export default defineComponent({
if (props.info.share) { if (props.info.share) {
if (menu.length > 0) menu.push(null); if (menu.length > 0) menu.push(null);
menu.push({ menu.push({
text: i18n.locale.share, text: i18n.ts.share,
icon: 'fas fa-share-alt', icon: 'fas fa-share-alt',
action: share action: share
}); });
@ -113,7 +113,7 @@ export default defineComponent({
if (menu.length > 0) menu.push(null); if (menu.length > 0) menu.push(null);
menu = menu.concat(props.menu); menu = menu.concat(props.menu);
} }
popupMenu(menu, ev.currentTarget || ev.target); popupMenu(menu, ev.currentTarget ?? ev.target);
}; };
const showTabsPopup = (ev: MouseEvent) => { const showTabsPopup = (ev: MouseEvent) => {
@ -126,7 +126,7 @@ export default defineComponent({
icon: tab.icon, icon: tab.icon,
action: tab.onClick, action: tab.onClick,
})); }));
popupMenu(menu, ev.currentTarget || ev.target); popupMenu(menu, ev.currentTarget ?? ev.target);
}; };
const preventDrag = (ev: TouchEvent) => { const preventDrag = (ev: TouchEvent) => {

View File

@ -24,16 +24,16 @@ let now = $ref(new Date());
const relative = $computed(() => { const relative = $computed(() => {
const ago = (now.getTime() - _time.getTime()) / 1000/*ms*/; const ago = (now.getTime() - _time.getTime()) / 1000/*ms*/;
return ( return (
ago >= 31536000 ? i18n.t('_ago.yearsAgo', { n: (~~(ago / 31536000)).toString() }) : ago >= 31536000 ? i18n.t('_ago.yearsAgo', { n: Math.round(ago / 31536000).toString() }) :
ago >= 2592000 ? i18n.t('_ago.monthsAgo', { n: (~~(ago / 2592000)).toString() }) : ago >= 2592000 ? i18n.t('_ago.monthsAgo', { n: Math.round(ago / 2592000).toString() }) :
ago >= 604800 ? i18n.t('_ago.weeksAgo', { n: (~~(ago / 604800)).toString() }) : ago >= 604800 ? i18n.t('_ago.weeksAgo', { n: Math.round(ago / 604800).toString() }) :
ago >= 86400 ? i18n.t('_ago.daysAgo', { n: (~~(ago / 86400)).toString() }) : ago >= 86400 ? i18n.t('_ago.daysAgo', { n: Math.round(ago / 86400).toString() }) :
ago >= 3600 ? i18n.t('_ago.hoursAgo', { n: (~~(ago / 3600)).toString() }) : ago >= 3600 ? i18n.t('_ago.hoursAgo', { n: Math.round(ago / 3600).toString() }) :
ago >= 60 ? i18n.t('_ago.minutesAgo', { n: (~~(ago / 60)).toString() }) : ago >= 60 ? i18n.t('_ago.minutesAgo', { n: (~~(ago / 60)).toString() }) :
ago >= 10 ? i18n.t('_ago.secondsAgo', { n: (~~(ago % 60)).toString() }) : ago >= 10 ? i18n.t('_ago.secondsAgo', { n: (~~(ago % 60)).toString() }) :
ago >= -1 ? i18n.locale._ago.justNow : ago >= -1 ? i18n.ts._ago.justNow :
ago < -1 ? i18n.locale._ago.future : ago < -1 ? i18n.ts._ago.future :
i18n.locale._ago.unknown); i18n.ts._ago.unknown);
}); });
function tick() { function tick() {

View File

@ -250,7 +250,7 @@ function menu(viaKeyboard = false): void {
function showRenoteMenu(viaKeyboard = false): void { function showRenoteMenu(viaKeyboard = false): void {
if (!isMyRenote) return; if (!isMyRenote) return;
os.popupMenu([{ os.popupMenu([{
text: i18n.locale.unrenote, text: i18n.ts.unrenote,
icon: 'fas fa-trash-alt', icon: 'fas fa-trash-alt',
danger: true, danger: true,
action: () => { action: () => {

View File

@ -10,13 +10,13 @@
:class="{ renote: isRenote }" :class="{ renote: isRenote }"
> >
<MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" class="reply-to"/> <MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" class="reply-to"/>
<div v-if="pinned" class="info"><i class="fas fa-thumbtack"></i> {{ i18n.locale.pinnedNote }}</div> <div v-if="pinned" class="info"><i class="fas fa-thumbtack"></i> {{ i18n.ts.pinnedNote }}</div>
<div v-if="appearNote._prId_" class="info"><i class="fas fa-bullhorn"></i> {{ i18n.locale.promotion }}<button class="_textButton hide" @click="readPromo()">{{ i18n.locale.hideThisNote }} <i class="fas fa-times"></i></button></div> <div v-if="appearNote._prId_" class="info"><i class="fas fa-bullhorn"></i> {{ i18n.ts.promotion }}<button class="_textButton hide" @click="readPromo()">{{ i18n.ts.hideThisNote }} <i class="fas fa-times"></i></button></div>
<div v-if="appearNote._featuredId_" class="info"><i class="fas fa-bolt"></i> {{ i18n.locale.featured }}</div> <div v-if="appearNote._featuredId_" class="info"><i class="fas fa-bolt"></i> {{ i18n.ts.featured }}</div>
<div v-if="isRenote" class="renote"> <div v-if="isRenote" class="renote">
<MkAvatar class="avatar" :user="note.user"/> <MkAvatar class="avatar" :user="note.user"/>
<i class="fas fa-retweet"></i> <i class="fas fa-retweet"></i>
<I18n :src="i18n.locale.renotedBy" tag="span"> <I18n :src="i18n.ts.renotedBy" tag="span">
<template #user> <template #user>
<MkA v-user-preview="note.userId" class="name" :to="userPage(note.user)"> <MkA v-user-preview="note.userId" class="name" :to="userPage(note.user)">
<MkUserName :user="note.user"/> <MkUserName :user="note.user"/>
@ -48,7 +48,7 @@
</p> </p>
<div v-show="appearNote.cw == null || showContent" class="content" :class="{ collapsed }"> <div v-show="appearNote.cw == null || showContent" class="content" :class="{ collapsed }">
<div class="text"> <div class="text">
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.locale.private }})</span> <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
<MkA v-if="appearNote.replyId" class="reply" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA> <MkA v-if="appearNote.replyId" class="reply" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA>
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/> <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
<a v-if="appearNote.renote != null" class="rp">RN:</a> <a v-if="appearNote.renote != null" class="rp">RN:</a>
@ -67,7 +67,7 @@
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" class="url-preview"/> <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" class="url-preview"/>
<div v-if="appearNote.renote" class="renote"><XNoteSimple :note="appearNote.renote"/></div> <div v-if="appearNote.renote" class="renote"><XNoteSimple :note="appearNote.renote"/></div>
<button v-if="collapsed" class="fade _button" @click="collapsed = false"> <button v-if="collapsed" class="fade _button" @click="collapsed = false">
<span>{{ i18n.locale.showMore }}</span> <span>{{ i18n.ts.showMore }}</span>
</button> </button>
</div> </div>
<MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><i class="fas fa-satellite-dish"></i> {{ appearNote.channel.name }}</MkA> <MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><i class="fas fa-satellite-dish"></i> {{ appearNote.channel.name }}</MkA>
@ -94,7 +94,7 @@
</article> </article>
</div> </div>
<div v-else class="muted" @click="muted = false"> <div v-else class="muted" @click="muted = false">
<I18n :src="i18n.locale.userSaysSomething" tag="small"> <I18n :src="i18n.ts.userSaysSomething" tag="small">
<template #name> <template #name>
<MkA v-user-preview="appearNote.userId" class="name" :to="userPage(appearNote.user)"> <MkA v-user-preview="appearNote.userId" class="name" :to="userPage(appearNote.user)">
<MkUserName :user="appearNote.user"/> <MkUserName :user="appearNote.user"/>
@ -238,7 +238,7 @@ function menu(viaKeyboard = false): void {
function showRenoteMenu(viaKeyboard = false): void { function showRenoteMenu(viaKeyboard = false): void {
if (!isMyRenote) return; if (!isMyRenote) return;
os.popupMenu([{ os.popupMenu([{
text: i18n.locale.unrenote, text: i18n.ts.unrenote,
icon: 'fas fa-trash-alt', icon: 'fas fa-trash-alt',
danger: true, danger: true,
action: () => { action: () => {

View File

@ -160,7 +160,7 @@ export default defineComponent({
action: () => { action: () => {
copyToClipboard(this.url); copyToClipboard(this.url);
} }
}], ev.currentTarget || ev.target); }], ev.currentTarget ?? ev.target);
}, },
back() { back() {

View File

@ -127,7 +127,7 @@ export default defineComponent({
text: this.$ts.attachCancel, text: this.$ts.attachCancel,
icon: 'fas fa-times-circle', icon: 'fas fa-times-circle',
action: () => { this.detachMedia(file.id) } action: () => { this.detachMedia(file.id) }
}], ev.currentTarget || ev.target).then(() => this.menu = null); }], ev.currentTarget ?? ev.target).then(() => this.menu = null);
} }
} }
}); });

View File

@ -8,28 +8,28 @@
> >
<header> <header>
<button v-if="!fixed" class="cancel _button" @click="cancel"><i class="fas fa-times"></i></button> <button v-if="!fixed" class="cancel _button" @click="cancel"><i class="fas fa-times"></i></button>
<button v-click-anime v-tooltip="i18n.locale.switchAccount" class="account _button" @click="openAccountMenu"> <button v-click-anime v-tooltip="i18n.ts.switchAccount" class="account _button" @click="openAccountMenu">
<MkAvatar :user="postAccount ?? $i" class="avatar"/> <MkAvatar :user="postAccount ?? $i" class="avatar"/>
</button> </button>
<div> <div>
<span class="text-count" :class="{ over: textLength > maxTextLength }">{{ maxTextLength - textLength }}</span> <span class="text-count" :class="{ over: textLength > maxTextLength }">{{ maxTextLength - textLength }}</span>
<span v-if="localOnly" class="local-only"><i class="fas fa-biohazard"></i></span> <span v-if="localOnly" class="local-only"><i class="fas fa-biohazard"></i></span>
<button ref="visibilityButton" v-tooltip="i18n.locale.visibility" class="_button visibility" :disabled="channel != null" @click="setVisibility"> <button ref="visibilityButton" v-tooltip="i18n.ts.visibility" class="_button visibility" :disabled="channel != null" @click="setVisibility">
<span v-if="visibility === 'public'"><i class="fas fa-globe"></i></span> <span v-if="visibility === 'public'"><i class="fas fa-globe"></i></span>
<span v-if="visibility === 'home'"><i class="fas fa-home"></i></span> <span v-if="visibility === 'home'"><i class="fas fa-home"></i></span>
<span v-if="visibility === 'followers'"><i class="fas fa-unlock"></i></span> <span v-if="visibility === 'followers'"><i class="fas fa-unlock"></i></span>
<span v-if="visibility === 'specified'"><i class="fas fa-envelope"></i></span> <span v-if="visibility === 'specified'"><i class="fas fa-envelope"></i></span>
</button> </button>
<button v-tooltip="i18n.locale.previewNoteText" class="_button preview" :class="{ active: showPreview }" @click="showPreview = !showPreview"><i class="fas fa-file-code"></i></button> <button v-tooltip="i18n.ts.previewNoteText" class="_button preview" :class="{ active: showPreview }" @click="showPreview = !showPreview"><i class="fas fa-file-code"></i></button>
<button class="submit _buttonGradate" :disabled="!canPost" data-cy-open-post-form-submit @click="post">{{ submitText }}<i :class="reply ? 'fas fa-reply' : renote ? 'fas fa-quote-right' : 'fas fa-paper-plane'"></i></button> <button class="submit _buttonGradate" :disabled="!canPost" data-cy-open-post-form-submit @click="post">{{ submitText }}<i :class="reply ? 'fas fa-reply' : renote ? 'fas fa-quote-right' : 'fas fa-paper-plane'"></i></button>
</div> </div>
</header> </header>
<div class="form" :class="{ fixed }"> <div class="form" :class="{ fixed }">
<XNoteSimple v-if="reply" class="preview" :note="reply"/> <XNoteSimple v-if="reply" class="preview" :note="reply"/>
<XNoteSimple v-if="renote" class="preview" :note="renote"/> <XNoteSimple v-if="renote" class="preview" :note="renote"/>
<div v-if="quoteId" class="with-quote"><i class="fas fa-quote-left"></i> {{ i18n.locale.quoteAttached }}<button @click="quoteId = null"><i class="fas fa-times"></i></button></div> <div v-if="quoteId" class="with-quote"><i class="fas fa-quote-left"></i> {{ i18n.ts.quoteAttached }}<button @click="quoteId = null"><i class="fas fa-times"></i></button></div>
<div v-if="visibility === 'specified'" class="to-specified"> <div v-if="visibility === 'specified'" class="to-specified">
<span style="margin-right: 8px;">{{ i18n.locale.recipient }}</span> <span style="margin-right: 8px;">{{ i18n.ts.recipient }}</span>
<div class="visibleUsers"> <div class="visibleUsers">
<span v-for="u in visibleUsers" :key="u.id"> <span v-for="u in visibleUsers" :key="u.id">
<MkAcct :user="u"/> <MkAcct :user="u"/>
@ -38,21 +38,21 @@
<button class="_buttonPrimary" @click="addVisibleUser"><i class="fas fa-plus fa-fw"></i></button> <button class="_buttonPrimary" @click="addVisibleUser"><i class="fas fa-plus fa-fw"></i></button>
</div> </div>
</div> </div>
<MkInfo v-if="hasNotSpecifiedMentions" warn class="hasNotSpecifiedMentions">{{ i18n.locale.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ i18n.locale.add }}</button></MkInfo> <MkInfo v-if="hasNotSpecifiedMentions" warn class="hasNotSpecifiedMentions">{{ i18n.ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ i18n.ts.add }}</button></MkInfo>
<input v-show="useCw" ref="cwInputEl" v-model="cw" class="cw" :placeholder="i18n.locale.annotation" @keydown="onKeydown"> <input v-show="useCw" ref="cwInputEl" v-model="cw" class="cw" :placeholder="i18n.ts.annotation" @keydown="onKeydown">
<textarea ref="textareaEl" v-model="text" class="text" :class="{ withCw: useCw }" :disabled="posting" :placeholder="placeholder" data-cy-post-form-text @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd"/> <textarea ref="textareaEl" v-model="text" class="text" :class="{ withCw: useCw }" :disabled="posting" :placeholder="placeholder" data-cy-post-form-text @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd"/>
<input v-show="withHashtags" ref="hashtagsInputEl" v-model="hashtags" class="hashtags" :placeholder="i18n.locale.hashtags" list="hashtags"> <input v-show="withHashtags" ref="hashtagsInputEl" v-model="hashtags" class="hashtags" :placeholder="i18n.ts.hashtags" list="hashtags">
<XPostFormAttaches class="attaches" :files="files" @updated="updateFiles" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/> <XPostFormAttaches class="attaches" :files="files" @updated="updateFiles" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/>
<XPollEditor v-if="poll" v-model="poll" @destroyed="poll = null"/> <XPollEditor v-if="poll" v-model="poll" @destroyed="poll = null"/>
<XNotePreview v-if="showPreview" class="preview" :text="text"/> <XNotePreview v-if="showPreview" class="preview" :text="text"/>
<footer> <footer>
<button v-tooltip="i18n.locale.attachFile" class="_button" @click="chooseFileFrom"><i class="fas fa-photo-video"></i></button> <button v-tooltip="i18n.ts.attachFile" class="_button" @click="chooseFileFrom"><i class="fas fa-photo-video"></i></button>
<button v-tooltip="i18n.locale.poll" class="_button" :class="{ active: poll }" @click="togglePoll"><i class="fas fa-poll-h"></i></button> <button v-tooltip="i18n.ts.poll" class="_button" :class="{ active: poll }" @click="togglePoll"><i class="fas fa-poll-h"></i></button>
<button v-tooltip="i18n.locale.useCw" class="_button" :class="{ active: useCw }" @click="useCw = !useCw"><i class="fas fa-eye-slash"></i></button> <button v-tooltip="i18n.ts.useCw" class="_button" :class="{ active: useCw }" @click="useCw = !useCw"><i class="fas fa-eye-slash"></i></button>
<button v-tooltip="i18n.locale.mention" class="_button" @click="insertMention"><i class="fas fa-at"></i></button> <button v-tooltip="i18n.ts.mention" class="_button" @click="insertMention"><i class="fas fa-at"></i></button>
<button v-tooltip="i18n.locale.hashtags" class="_button" :class="{ active: withHashtags }" @click="withHashtags = !withHashtags"><i class="fas fa-hashtag"></i></button> <button v-tooltip="i18n.ts.hashtags" class="_button" :class="{ active: withHashtags }" @click="withHashtags = !withHashtags"><i class="fas fa-hashtag"></i></button>
<button v-tooltip="i18n.locale.emoji" class="_button" @click="insertEmoji"><i class="fas fa-laugh-squint"></i></button> <button v-tooltip="i18n.ts.emoji" class="_button" @click="insertEmoji"><i class="fas fa-laugh-squint"></i></button>
<button v-if="postFormActions.length > 0" v-tooltip="i18n.locale.plugin" class="_button" @click="showActions"><i class="fas fa-plug"></i></button> <button v-if="postFormActions.length > 0" v-tooltip="i18n.ts.plugin" class="_button" @click="showActions"><i class="fas fa-plug"></i></button>
</footer> </footer>
<datalist id="hashtags"> <datalist id="hashtags">
<option v-for="hashtag in recentHashtags" :key="hashtag" :value="hashtag"/> <option v-for="hashtag in recentHashtags" :key="hashtag" :value="hashtag"/>
@ -165,19 +165,19 @@ const draftKey = $computed((): string => {
const placeholder = $computed((): string => { const placeholder = $computed((): string => {
if (props.renote) { if (props.renote) {
return i18n.locale._postForm.quotePlaceholder; return i18n.ts._postForm.quotePlaceholder;
} else if (props.reply) { } else if (props.reply) {
return i18n.locale._postForm.replyPlaceholder; return i18n.ts._postForm.replyPlaceholder;
} else if (props.channel) { } else if (props.channel) {
return i18n.locale._postForm.channelPlaceholder; return i18n.ts._postForm.channelPlaceholder;
} else { } else {
const xs = [ const xs = [
i18n.locale._postForm._placeholders.a, i18n.ts._postForm._placeholders.a,
i18n.locale._postForm._placeholders.b, i18n.ts._postForm._placeholders.b,
i18n.locale._postForm._placeholders.c, i18n.ts._postForm._placeholders.c,
i18n.locale._postForm._placeholders.d, i18n.ts._postForm._placeholders.d,
i18n.locale._postForm._placeholders.e, i18n.ts._postForm._placeholders.e,
i18n.locale._postForm._placeholders.f i18n.ts._postForm._placeholders.f
]; ];
return xs[Math.floor(Math.random() * xs.length)]; return xs[Math.floor(Math.random() * xs.length)];
} }
@ -185,10 +185,10 @@ const placeholder = $computed((): string => {
const submitText = $computed((): string => { const submitText = $computed((): string => {
return props.renote return props.renote
? i18n.locale.quote ? i18n.ts.quote
: props.reply : props.reply
? i18n.locale.reply ? i18n.ts.reply
: i18n.locale.note; : i18n.ts.note;
}); });
const textLength = $computed((): number => { const textLength = $computed((): number => {
@ -342,7 +342,7 @@ function focus() {
} }
function chooseFileFrom(ev) { function chooseFileFrom(ev) {
selectFiles(ev.currentTarget || ev.target, i18n.locale.attachFile).then(files_ => { selectFiles(ev.currentTarget ?? ev.target, i18n.ts.attachFile).then(files_ => {
for (const file of files_) { for (const file of files_) {
files.push(file); files.push(file);
} }
@ -447,7 +447,7 @@ async function onPaste(e: ClipboardEvent) {
os.confirm({ os.confirm({
type: 'info', type: 'info',
text: i18n.locale.quoteQuestion, text: i18n.ts.quoteQuestion,
}).then(({ canceled }) => { }).then(({ canceled }) => {
if (canceled) { if (canceled) {
insertTextAtCursor(textareaEl, paste); insertTextAtCursor(textareaEl, paste);
@ -592,7 +592,7 @@ function insertMention() {
} }
async function insertEmoji(ev: MouseEvent) { async function insertEmoji(ev: MouseEvent) {
os.openEmojiPicker(ev.currentTarget || ev.target, {}, textareaEl); os.openEmojiPicker(ev.currentTarget ?? ev.target, {}, textareaEl);
} }
function showActions(ev) { function showActions(ev) {
@ -605,7 +605,7 @@ function showActions(ev) {
if (key === 'text') { text = value; } if (key === 'text') { text = value; }
}); });
} }
})), ev.currentTarget || ev.target); })), ev.currentTarget ?? ev.target);
} }
let postAccount = $ref<misskey.entities.UserDetailed | null>(null); let postAccount = $ref<misskey.entities.UserDetailed | null>(null);

View File

@ -59,7 +59,7 @@ export default defineComponent({
const renote = (viaKeyboard = false) => { const renote = (viaKeyboard = false) => {
pleaseLogin(); pleaseLogin();
os.popupMenu([{ os.popupMenu([{
text: i18n.locale.renote, text: i18n.ts.renote,
icon: 'fas fa-retweet', icon: 'fas fa-retweet',
action: () => { action: () => {
os.api('notes/create', { os.api('notes/create', {
@ -67,7 +67,7 @@ export default defineComponent({
}); });
} }
}, { }, {
text: i18n.locale.quote, text: i18n.ts.quote,
icon: 'fas fa-quote-right', icon: 'fas fa-quote-right',
action: () => { action: () => {
os.post({ os.post({

View File

@ -109,7 +109,7 @@ export default defineComponent({
text: 'Delete some bananas', text: 'Delete some bananas',
danger: true, danger: true,
action: () => {}, action: () => {},
}], ev.currentTarget || ev.target); }], ev.currentTarget ?? ev.target);
}, },
} }
}); });

View File

@ -1,5 +1,5 @@
<template> <template>
<transition :name="$store.state.animation ? (type === 'drawer') ? 'modal-drawer' : (type === 'popup') ? 'modal-popup' : 'modal' : ''" :duration="$store.state.animation ? 200 : 0" appear @after-leave="$emit('closed')" @enter="$emit('opening')" @after-enter="childRendered"> <transition :name="$store.state.animation ? (type === 'drawer') ? 'modal-drawer' : (type === 'popup') ? 'modal-popup' : 'modal' : ''" :duration="$store.state.animation ? 200 : 0" appear @after-leave="emit('closed')" @enter="emit('opening')" @after-enter="childRendered">
<div v-show="manualShowing != null ? manualShowing : showing" v-hotkey.global="keymap" class="qzhlnise" :class="{ drawer: type === 'drawer', dialog: type === 'dialog' || type === 'dialog:top', popup: type === 'popup' }" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }"> <div v-show="manualShowing != null ? manualShowing : showing" v-hotkey.global="keymap" class="qzhlnise" :class="{ drawer: type === 'drawer', dialog: type === 'dialog' || type === 'dialog:top', popup: type === 'popup' }" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
<div class="bg _modalBg" :class="{ transparent: transparentBg && (type === 'popup') }" :style="{ zIndex }" @click="onBgClick" @contextmenu.prevent.stop="() => {}"></div> <div class="bg _modalBg" :class="{ transparent: transparentBg && (type === 'popup') }" :style="{ zIndex }" @click="onBgClick" @contextmenu.prevent.stop="() => {}"></div>
<div ref="content" class="content" :class="{ fixed, top: type === 'dialog:top' }" :style="{ zIndex }" @click.self="onBgClick"> <div ref="content" class="content" :class="{ fixed, top: type === 'dialog:top' }" :style="{ zIndex }" @click.self="onBgClick">
@ -9,8 +9,8 @@
</transition> </transition>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent, nextTick, onMounted, computed, PropType, ref, watch } from 'vue'; import { nextTick, onMounted, computed, ref, watch, provide } from 'vue';
import * as os from '@/os'; import * as os from '@/os';
import { isTouchUsing } from '@/scripts/touch'; import { isTouchUsing } from '@/scripts/touch';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
@ -25,234 +25,206 @@ function getFixedContainer(el: Element | null): Element | null {
} }
} }
export default defineComponent({ type ModalTypes = 'popup' | 'dialog' | 'dialog:top' | 'drawer';
provide: {
modal: true
},
props: { const props = withDefaults(defineProps<{
manualShowing: { manualShowing?: boolean | null;
type: Boolean, srcCenter?: boolean;
required: false, src?: HTMLElement;
default: null, preferType?: ModalTypes | 'auto';
}, zPriority?: 'low' | 'middle' | 'high';
srcCenter: { noOverlap?: boolean;
type: Boolean, transparentBg?: boolean;
required: false }>(), {
}, manualShowing: null,
src: { src: null,
type: Object as PropType<HTMLElement>, preferType: 'auto',
required: false, zPriority: 'low',
default: null, noOverlap: true,
}, transparentBg: false,
preferType: { });
required: false,
type: String,
default: 'auto',
},
zPriority: {
type: String as PropType<'low' | 'middle' | 'high'>,
required: false,
default: 'low',
},
noOverlap: {
type: Boolean,
required: false,
default: true,
},
transparentBg: {
type: Boolean,
required: false,
default: false,
},
},
emits: ['opening', 'click', 'esc', 'close', 'closed'], const emit = defineEmits<{
(ev: 'opening'): void;
(ev: 'click'): void;
(ev: 'esc'): void;
(ev: 'close'): void;
(ev: 'closed'): void;
}>();
setup(props, context) { provide('modal', true);
const maxHeight = ref<number>();
const fixed = ref(false);
const transformOrigin = ref('center');
const showing = ref(true);
const content = ref<HTMLElement>();
const zIndex = os.claimZIndex(props.zPriority);
const type = computed(() => {
if (props.preferType === 'auto') {
if (!defaultStore.state.disableDrawer && isTouchUsing && window.innerWidth < 500 && window.innerHeight < 1000) {
return 'drawer';
} else {
return props.src != null ? 'popup' : 'dialog';
}
} else {
return props.preferType;
}
});
let contentClicking = false;
const close = () => { const maxHeight = ref<number>();
// eslint-disable-next-line vue/no-mutating-props const fixed = ref(false);
if (props.src) props.src.style.pointerEvents = 'auto'; const transformOrigin = ref('center');
showing.value = false; const showing = ref(true);
context.emit('close'); const content = ref<HTMLElement>();
}; const zIndex = os.claimZIndex(props.zPriority);
const type = computed(() => {
if (props.preferType === 'auto') {
if (!defaultStore.state.disableDrawer && isTouchUsing && window.innerWidth < 500 && window.innerHeight < 1000) {
return 'drawer';
} else {
return props.src != null ? 'popup' : 'dialog';
}
} else {
return props.preferType!;
}
});
const onBgClick = () => { let contentClicking = false;
if (contentClicking) return;
context.emit('click');
};
if (type.value === 'drawer') { const close = () => {
maxHeight.value = window.innerHeight / 2; // eslint-disable-next-line vue/no-mutating-props
if (props.src) props.src.style.pointerEvents = 'auto';
showing.value = false;
emit('close');
};
const onBgClick = () => {
if (contentClicking) return;
emit('click');
};
if (type.value === 'drawer') {
maxHeight.value = window.innerHeight / 2;
}
const keymap = {
'esc': () => emit('esc'),
};
const MARGIN = 16;
const align = () => {
if (props.src == null) return;
if (type.value === 'drawer') return;
const popover = content.value!;
if (popover == null) return;
const rect = props.src.getBoundingClientRect();
const width = popover.offsetWidth;
const height = popover.offsetHeight;
let left;
let top;
if (props.srcCenter) {
const x = rect.left + (fixed.value ? 0 : window.pageXOffset) + (props.src.offsetWidth / 2);
const y = rect.top + (fixed.value ? 0 : window.pageYOffset) + (props.src.offsetHeight / 2);
left = (x - (width / 2));
top = (y - (height / 2));
} else {
const x = rect.left + (fixed.value ? 0 : window.pageXOffset) + (props.src.offsetWidth / 2);
const y = rect.top + (fixed.value ? 0 : window.pageYOffset) + props.src.offsetHeight;
left = (x - (width / 2));
top = y;
}
if (fixed.value) {
//
if (left + width > window.innerWidth) {
left = window.innerWidth - width;
} }
const keymap = { //
'esc': () => context.emit('esc'), if (top + height > (window.innerHeight - MARGIN)) {
}; if (props.noOverlap) {
const underSpace = (window.innerHeight - MARGIN) - top;
const MARGIN = 16; const upperSpace = (rect.top - MARGIN);
if (underSpace >= (upperSpace / 3)) {
const align = () => { maxHeight.value = underSpace;
if (props.src == null) return; } else {
if (type.value === 'drawer') return; maxHeight.value = upperSpace;
top = (upperSpace + MARGIN) - height;
const popover = content.value!;
if (popover == null) return;
const rect = props.src.getBoundingClientRect();
const width = popover.offsetWidth;
const height = popover.offsetHeight;
let left;
let top;
if (props.srcCenter) {
const x = rect.left + (fixed.value ? 0 : window.pageXOffset) + (props.src.offsetWidth / 2);
const y = rect.top + (fixed.value ? 0 : window.pageYOffset) + (props.src.offsetHeight / 2);
left = (x - (width / 2));
top = (y - (height / 2));
} else {
const x = rect.left + (fixed.value ? 0 : window.pageXOffset) + (props.src.offsetWidth / 2);
const y = rect.top + (fixed.value ? 0 : window.pageYOffset) + props.src.offsetHeight;
left = (x - (width / 2));
top = y;
}
if (fixed.value) {
//
if (left + width > window.innerWidth) {
left = window.innerWidth - width;
}
//
if (top + height > (window.innerHeight - MARGIN)) {
if (props.noOverlap) {
const underSpace = (window.innerHeight - MARGIN) - top;
const upperSpace = (rect.top - MARGIN);
if (underSpace >= (upperSpace / 3)) {
maxHeight.value = underSpace;
} else {
maxHeight.value = upperSpace;
top = (upperSpace + MARGIN) - height;
}
} else {
top = (window.innerHeight - MARGIN) - height;
}
} }
} else { } else {
// top = (window.innerHeight - MARGIN) - height;
if (left + width - window.pageXOffset > window.innerWidth) { }
left = window.innerWidth - width + window.pageXOffset - 1; }
} else {
//
if (left + width - window.pageXOffset > window.innerWidth) {
left = window.innerWidth - width + window.pageXOffset - 1;
}
//
if (top + height - window.pageYOffset > (window.innerHeight - MARGIN)) {
if (props.noOverlap) {
const underSpace = (window.innerHeight - MARGIN) - (top - window.pageYOffset);
const upperSpace = (rect.top - MARGIN);
if (underSpace >= (upperSpace / 3)) {
maxHeight.value = underSpace;
} else {
maxHeight.value = upperSpace;
top = window.pageYOffset + ((upperSpace + MARGIN) - height);
} }
//
if (top + height - window.pageYOffset > (window.innerHeight - MARGIN)) {
if (props.noOverlap) {
const underSpace = (window.innerHeight - MARGIN) - (top - window.pageYOffset);
const upperSpace = (rect.top - MARGIN);
if (underSpace >= (upperSpace / 3)) {
maxHeight.value = underSpace;
} else {
maxHeight.value = upperSpace;
top = window.pageYOffset + ((upperSpace + MARGIN) - height);
}
} else {
top = (window.innerHeight - MARGIN) - height + window.pageYOffset - 1;
}
}
}
if (top < 0) {
top = MARGIN;
}
if (left < 0) {
left = 0;
}
if (top > rect.top + (fixed.value ? 0 : window.pageYOffset)) {
transformOrigin.value = 'center top';
} else if ((top + height) <= rect.top + (fixed.value ? 0 : window.pageYOffset)) {
transformOrigin.value = 'center bottom';
} else { } else {
transformOrigin.value = 'center'; top = (window.innerHeight - MARGIN) - height + window.pageYOffset - 1;
} }
}
}
popover.style.left = left + 'px'; if (top < 0) {
popover.style.top = top + 'px'; top = MARGIN;
}; }
const childRendered = () => { if (left < 0) {
// left = 0;
const el = content.value!.children[0]; }
el.addEventListener('mousedown', e => {
contentClicking = true;
window.addEventListener('mouseup', e => {
// click mouseup
window.setTimeout(() => {
contentClicking = false;
}, 100);
}, { passive: true, once: true });
}, { passive: true });
};
onMounted(() => { if (top > rect.top + (fixed.value ? 0 : window.pageYOffset)) {
watch(() => props.src, async () => { transformOrigin.value = 'center top';
if (props.src) { } else if ((top + height) <= rect.top + (fixed.value ? 0 : window.pageYOffset)) {
// eslint-disable-next-line vue/no-mutating-props transformOrigin.value = 'center bottom';
props.src.style.pointerEvents = 'none'; } else {
} transformOrigin.value = 'center';
fixed.value = (type.value === 'drawer') || (getFixedContainer(props.src) != null); }
await nextTick() popover.style.left = left + 'px';
popover.style.top = top + 'px';
align(); };
}, { immediate: true, });
nextTick(() => { const childRendered = () => {
const popover = content.value; //
new ResizeObserver((entries, observer) => { const el = content.value!.children[0];
align(); el.addEventListener('mousedown', ev => {
}).observe(popover!); contentClicking = true;
}); window.addEventListener('mouseup', ev => {
}); // click mouseup
window.setTimeout(() => {
contentClicking = false;
}, 100);
}, { passive: true, once: true });
}, { passive: true });
};
return { onMounted(() => {
showing, watch(() => props.src, async () => {
type, if (props.src) {
fixed, // eslint-disable-next-line vue/no-mutating-props
content, props.src.style.pointerEvents = 'none';
transformOrigin, }
maxHeight, fixed.value = (type.value === 'drawer') || (getFixedContainer(props.src) != null);
close,
zIndex, await nextTick()
keymap,
onBgClick, align();
childRendered, }, { immediate: true, });
};
}, nextTick(() => {
const popover = content.value;
new ResizeObserver((entries, observer) => {
align();
}).observe(popover!);
});
});
defineExpose({
close,
}); });
</script> </script>

View File

@ -13,10 +13,10 @@ const props = defineProps<{
const text = $computed(() => { const text = $computed(() => {
switch (props.user.onlineStatus) { switch (props.user.onlineStatus) {
case 'online': return i18n.locale.online; case 'online': return i18n.ts.online;
case 'active': return i18n.locale.active; case 'active': return i18n.ts.active;
case 'offline': return i18n.locale.offline; case 'offline': return i18n.ts.offline;
case 'unknown': return i18n.locale.unknown; case 'unknown': return i18n.ts.unknown;
} }
}); });
</script> </script>

View File

@ -185,7 +185,7 @@ app.config.globalProperties = {
$store: defaultStore, $store: defaultStore,
$instance: instance, $instance: instance,
$t: i18n.t, $t: i18n.t,
$ts: i18n.locale, $ts: i18n.ts,
}; };
app.use(router); app.use(router);
@ -299,8 +299,8 @@ stream.on('_disconnected_', async () => {
reloadDialogShowing = true; reloadDialogShowing = true;
const { canceled } = await confirm({ const { canceled } = await confirm({
type: 'warning', type: 'warning',
title: i18n.locale.disconnectedFromServer, title: i18n.ts.disconnectedFromServer,
text: i18n.locale.reloadConfirm, text: i18n.ts.reloadConfirm,
}); });
reloadDialogShowing = false; reloadDialogShowing = false;
if (!canceled) { if (!canceled) {
@ -324,7 +324,7 @@ if ($i) {
if ($i.isDeleted) { if ($i.isDeleted) {
alert({ alert({
type: 'warning', type: 'warning',
text: i18n.locale.accountDeletionInProgress, text: i18n.ts.accountDeletionInProgress,
}); });
} }

View File

@ -73,12 +73,12 @@ export const menuDef = reactive({
})), null, { })), null, {
type: 'link', type: 'link',
to: '/my/lists', to: '/my/lists',
text: i18n.locale.manageLists, text: i18n.ts.manageLists,
icon: 'fas fa-cog', icon: 'fas fa-cog',
}]; }];
items.value = _items; items.value = _items;
}); });
os.popupMenu(items, ev.currentTarget || ev.target); os.popupMenu(items, ev.currentTarget ?? ev.target);
}, },
}, },
groups: { groups: {
@ -104,12 +104,12 @@ export const menuDef = reactive({
})), null, { })), null, {
type: 'link', type: 'link',
to: '/my/antennas', to: '/my/antennas',
text: i18n.locale.manageAntennas, text: i18n.ts.manageAntennas,
icon: 'fas fa-cog', icon: 'fas fa-cog',
}]; }];
items.value = _items; items.value = _items;
}); });
os.popupMenu(items, ev.currentTarget || ev.target); os.popupMenu(items, ev.currentTarget ?? ev.target);
}, },
}, },
mentions: { mentions: {
@ -173,34 +173,34 @@ export const menuDef = reactive({
icon: 'fas fa-columns', icon: 'fas fa-columns',
action: (ev) => { action: (ev) => {
os.popupMenu([{ os.popupMenu([{
text: i18n.locale.default, text: i18n.ts.default,
active: ui === 'default' || ui === null, active: ui === 'default' || ui === null,
action: () => { action: () => {
localStorage.setItem('ui', 'default'); localStorage.setItem('ui', 'default');
unisonReload(); unisonReload();
} }
}, { }, {
text: i18n.locale.deck, text: i18n.ts.deck,
active: ui === 'deck', active: ui === 'deck',
action: () => { action: () => {
localStorage.setItem('ui', 'deck'); localStorage.setItem('ui', 'deck');
unisonReload(); unisonReload();
} }
}, { }, {
text: i18n.locale.classic, text: i18n.ts.classic,
active: ui === 'classic', active: ui === 'classic',
action: () => { action: () => {
localStorage.setItem('ui', 'classic'); localStorage.setItem('ui', 'classic');
unisonReload(); unisonReload();
} }
}, /*{ }, /*{
text: i18n.locale.desktop + ' (β)', text: i18n.ts.desktop + ' (β)',
active: ui === 'desktop', active: ui === 'desktop',
action: () => { action: () => {
localStorage.setItem('ui', 'desktop'); localStorage.setItem('ui', 'desktop');
unisonReload(); unisonReload();
} }
}*/], ev.currentTarget || ev.target); }*/], ev.currentTarget ?? ev.target);
}, },
}, },
}); });

View File

@ -403,7 +403,7 @@ export async function selectDriveFolder(multiple: boolean) {
}); });
} }
export async function pickEmoji(src?: HTMLElement, opts) { export async function pickEmoji(src: HTMLElement | null, opts) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
popup(import('@/components/emoji-picker-dialog.vue'), { popup(import('@/components/emoji-picker-dialog.vue'), {
src, src,

View File

@ -3,15 +3,15 @@
<transition :name="$store.state.animation ? 'zoom' : ''" appear> <transition :name="$store.state.animation ? 'zoom' : ''" appear>
<div v-show="loaded" class="mjndxjch"> <div v-show="loaded" class="mjndxjch">
<img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/> <img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
<p><b><i class="fas fa-exclamation-triangle"></i> {{ i18n.locale.pageLoadError }}</b></p> <p><b><i class="fas fa-exclamation-triangle"></i> {{ i18n.ts.pageLoadError }}</b></p>
<p v-if="meta && (version === meta.version)">{{ i18n.locale.pageLoadErrorDescription }}</p> <p v-if="meta && (version === meta.version)">{{ i18n.ts.pageLoadErrorDescription }}</p>
<p v-else-if="serverIsDead">{{ i18n.locale.serverIsDead }}</p> <p v-else-if="serverIsDead">{{ i18n.ts.serverIsDead }}</p>
<template v-else> <template v-else>
<p>{{ i18n.locale.newVersionOfClientAvailable }}</p> <p>{{ i18n.ts.newVersionOfClientAvailable }}</p>
<p>{{ i18n.locale.youShouldUpgradeClient }}</p> <p>{{ i18n.ts.youShouldUpgradeClient }}</p>
<MkButton class="button primary" @click="reload">{{ i18n.locale.reload }}</MkButton> <MkButton class="button primary" @click="reload">{{ i18n.ts.reload }}</MkButton>
</template> </template>
<p><MkA to="/docs/general/troubleshooting" class="_link">{{ i18n.locale.troubleshooting }}</MkA></p> <p><MkA to="/docs/general/troubleshooting" class="_link">{{ i18n.ts.troubleshooting }}</MkA></p>
<p v-if="error" class="error">ERROR: {{ error }}</p> <p v-if="error" class="error">ERROR: {{ error }}</p>
</div> </div>
</transition> </transition>
@ -54,7 +54,7 @@ function reload() {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.error, title: i18n.ts.error,
icon: 'fas fa-exclamation-triangle', icon: 'fas fa-exclamation-triangle',
}, },
}); });

View File

@ -10,7 +10,7 @@
<span v-for="emoji in easterEggEmojis" :key="emoji.id" class="emoji" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"><MkEmoji class="emoji" :emoji="emoji.emoji" :custom-emojis="$instance.emojis" :is-reaction="false" :normal="true" :no-style="true"/></span> <span v-for="emoji in easterEggEmojis" :key="emoji.id" class="emoji" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"><MkEmoji class="emoji" :emoji="emoji.emoji" :custom-emojis="$instance.emojis" :is-reaction="false" :normal="true" :no-style="true"/></span>
</div> </div>
<div class="_formBlock" style="text-align: center;"> <div class="_formBlock" style="text-align: center;">
{{ i18n.locale._aboutMisskey.about }}<br><a href="https://misskey-hub.net/docs/misskey.html" target="_blank" class="_link">{{ i18n.locale.learnMore }}</a> {{ i18n.ts._aboutMisskey.about }}<br><a href="https://misskey-hub.net/docs/misskey.html" target="_blank" class="_link">{{ i18n.ts.learnMore }}</a>
</div> </div>
<div class="_formBlock" style="text-align: center;"> <div class="_formBlock" style="text-align: center;">
<MkButton primary rounded inline @click="iLoveMisskey">I <Mfm text="$[jelly ❤]"/> #Misskey</MkButton> <MkButton primary rounded inline @click="iLoveMisskey">I <Mfm text="$[jelly ❤]"/> #Misskey</MkButton>
@ -19,23 +19,23 @@
<div class="_formLinks"> <div class="_formLinks">
<FormLink to="https://github.com/misskey-dev/misskey" external> <FormLink to="https://github.com/misskey-dev/misskey" external>
<template #icon><i class="fas fa-code"></i></template> <template #icon><i class="fas fa-code"></i></template>
{{ i18n.locale._aboutMisskey.source }} {{ i18n.ts._aboutMisskey.source }}
<template #suffix>GitHub</template> <template #suffix>GitHub</template>
</FormLink> </FormLink>
<FormLink to="https://crowdin.com/project/misskey" external> <FormLink to="https://crowdin.com/project/misskey" external>
<template #icon><i class="fas fa-language"></i></template> <template #icon><i class="fas fa-language"></i></template>
{{ i18n.locale._aboutMisskey.translation }} {{ i18n.ts._aboutMisskey.translation }}
<template #suffix>Crowdin</template> <template #suffix>Crowdin</template>
</FormLink> </FormLink>
<FormLink to="https://www.patreon.com/syuilo" external> <FormLink to="https://www.patreon.com/syuilo" external>
<template #icon><i class="fas fa-hand-holding-medical"></i></template> <template #icon><i class="fas fa-hand-holding-medical"></i></template>
{{ i18n.locale._aboutMisskey.donate }} {{ i18n.ts._aboutMisskey.donate }}
<template #suffix>Patreon</template> <template #suffix>Patreon</template>
</FormLink> </FormLink>
</div> </div>
</FormSection> </FormSection>
<FormSection> <FormSection>
<template #label>{{ i18n.locale._aboutMisskey.contributors }}</template> <template #label>{{ i18n.ts._aboutMisskey.contributors }}</template>
<div class="_formLinks"> <div class="_formLinks">
<FormLink to="https://github.com/syuilo" external>@syuilo</FormLink> <FormLink to="https://github.com/syuilo" external>@syuilo</FormLink>
<FormLink to="https://github.com/AyaMorisawa" external>@AyaMorisawa</FormLink> <FormLink to="https://github.com/AyaMorisawa" external>@AyaMorisawa</FormLink>
@ -47,12 +47,12 @@
<FormLink to="https://github.com/u1-liquid" external>@u1-liquid</FormLink> <FormLink to="https://github.com/u1-liquid" external>@u1-liquid</FormLink>
<FormLink to="https://github.com/marihachi" external>@marihachi</FormLink> <FormLink to="https://github.com/marihachi" external>@marihachi</FormLink>
</div> </div>
<template #caption><MkLink url="https://github.com/misskey-dev/misskey/graphs/contributors">{{ i18n.locale._aboutMisskey.allContributors }}</MkLink></template> <template #caption><MkLink url="https://github.com/misskey-dev/misskey/graphs/contributors">{{ i18n.ts._aboutMisskey.allContributors }}</MkLink></template>
</FormSection> </FormSection>
<FormSection> <FormSection>
<template #label><Mfm text="$[jelly ❤]"/> {{ i18n.locale._aboutMisskey.patrons }}</template> <template #label><Mfm text="$[jelly ❤]"/> {{ i18n.ts._aboutMisskey.patrons }}</template>
<div v-for="patron in patrons" :key="patron">{{ patron }}</div> <div v-for="patron in patrons" :key="patron">{{ patron }}</div>
<template #caption>{{ i18n.locale._aboutMisskey.morePatrons }}</template> <template #caption>{{ i18n.ts._aboutMisskey.morePatrons }}</template>
</FormSection> </FormSection>
</div> </div>
</MkSpacer> </MkSpacer>
@ -194,7 +194,7 @@ onBeforeUnmount(() => {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.aboutMisskey, title: i18n.ts.aboutMisskey,
icon: null, icon: null,
bg: 'var(--bg)', bg: 'var(--bg)',
}, },

View File

@ -90,7 +90,7 @@ const initStats = () => os.api('stats', {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.instanceInfo, title: i18n.ts.instanceInfo,
icon: 'fas fa-info-circle', icon: 'fas fa-info-circle',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },

View File

@ -118,7 +118,7 @@ const toggleSelect = (emoji) => {
}; };
const add = async (ev: MouseEvent) => { const add = async (ev: MouseEvent) => {
const files = await selectFiles(ev.currentTarget || ev.target, null); const files = await selectFiles(ev.currentTarget ?? ev.target, null);
const promise = Promise.all(files.map(file => os.api('admin/emoji/add', { const promise = Promise.all(files.map(file => os.api('admin/emoji/add', {
fileId: file.id, fileId: file.id,
@ -157,23 +157,23 @@ const remoteMenu = (emoji, ev: MouseEvent) => {
type: 'label', type: 'label',
text: ':' + emoji.name + ':', text: ':' + emoji.name + ':',
}, { }, {
text: i18n.locale.import, text: i18n.ts.import,
icon: 'fas fa-plus', icon: 'fas fa-plus',
action: () => { im(emoji) } action: () => { im(emoji) }
}], ev.currentTarget || ev.target); }], ev.currentTarget ?? ev.target);
}; };
const menu = (ev: MouseEvent) => { const menu = (ev: MouseEvent) => {
os.popupMenu([{ os.popupMenu([{
icon: 'fas fa-download', icon: 'fas fa-download',
text: i18n.locale.export, text: i18n.ts.export,
action: async () => { action: async () => {
os.api('export-custom-emojis', { os.api('export-custom-emojis', {
}) })
.then(() => { .then(() => {
os.alert({ os.alert({
type: 'info', type: 'info',
text: i18n.locale.exportRequested, text: i18n.ts.exportRequested,
}); });
}).catch((e) => { }).catch((e) => {
os.alert({ os.alert({
@ -184,16 +184,16 @@ const menu = (ev: MouseEvent) => {
} }
}, { }, {
icon: 'fas fa-upload', icon: 'fas fa-upload',
text: i18n.locale.import, text: i18n.ts.import,
action: async () => { action: async () => {
const file = await selectFile(ev.currentTarget || ev.target); const file = await selectFile(ev.currentTarget ?? ev.target);
os.api('admin/emoji/import-zip', { os.api('admin/emoji/import-zip', {
fileId: file.id, fileId: file.id,
}) })
.then(() => { .then(() => {
os.alert({ os.alert({
type: 'info', type: 'info',
text: i18n.locale.importRequested, text: i18n.ts.importRequested,
}); });
}).catch((e) => { }).catch((e) => {
os.alert({ os.alert({
@ -202,7 +202,7 @@ const menu = (ev: MouseEvent) => {
}); });
}); });
} }
}], ev.currentTarget || ev.target); }], ev.currentTarget ?? ev.target);
}; };
const setCategoryBulk = async () => { const setCategoryBulk = async () => {
@ -256,7 +256,7 @@ const setTagBulk = async () => {
const delBulk = async () => { const delBulk = async () => {
const { canceled } = await os.confirm({ const { canceled } = await os.confirm({
type: 'warning', type: 'warning',
text: i18n.locale.deleteConfirm, text: i18n.ts.deleteConfirm,
}); });
if (canceled) return; if (canceled) return;
await os.apiWithDialog('admin/emoji/delete-bulk', { await os.apiWithDialog('admin/emoji/delete-bulk', {
@ -267,13 +267,13 @@ const delBulk = async () => {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: computed(() => ({ [symbols.PAGE_INFO]: computed(() => ({
title: i18n.locale.customEmojis, title: i18n.ts.customEmojis,
icon: 'fas fa-laugh', icon: 'fas fa-laugh',
bg: 'var(--bg)', bg: 'var(--bg)',
actions: [{ actions: [{
asFullButton: true, asFullButton: true,
icon: 'fas fa-plus', icon: 'fas fa-plus',
text: i18n.locale.addEmoji, text: i18n.ts.addEmoji,
handler: add, handler: add,
}, { }, {
icon: 'fas fa-ellipsis-h', icon: 'fas fa-ellipsis-h',
@ -281,11 +281,11 @@ defineExpose({
}], }],
tabs: [{ tabs: [{
active: tab.value === 'local', active: tab.value === 'local',
title: i18n.locale.local, title: i18n.ts.local,
onClick: () => { tab.value = 'local'; }, onClick: () => { tab.value = 'local'; },
}, { }, {
active: tab.value === 'remote', active: tab.value === 'remote',
title: i18n.locale.remote, title: i18n.ts.remote,
onClick: () => { tab.value = 'remote'; }, onClick: () => { tab.value = 'remote'; },
},] },]
})), })),

View File

@ -55,7 +55,7 @@ export default defineComponent({
setup(props, context) { setup(props, context) {
const indexInfo = { const indexInfo = {
title: i18n.locale.controlPanel, title: i18n.ts.controlPanel,
icon: 'fas fa-cog', icon: 'fas fa-cog',
bg: 'var(--bg)', bg: 'var(--bg)',
hideHeader: true, hideHeader: true,
@ -91,119 +91,119 @@ export default defineComponent({
}); });
const menuDef = computed(() => [{ const menuDef = computed(() => [{
title: i18n.locale.quickAction, title: i18n.ts.quickAction,
items: [{ items: [{
type: 'button', type: 'button',
icon: 'fas fa-search', icon: 'fas fa-search',
text: i18n.locale.lookup, text: i18n.ts.lookup,
action: lookup, action: lookup,
}, ...(instance.disableRegistration ? [{ }, ...(instance.disableRegistration ? [{
type: 'button', type: 'button',
icon: 'fas fa-user', icon: 'fas fa-user',
text: i18n.locale.invite, text: i18n.ts.invite,
action: invite, action: invite,
}] : [])], }] : [])],
}, { }, {
title: i18n.locale.administration, title: i18n.ts.administration,
items: [{ items: [{
icon: 'fas fa-tachometer-alt', icon: 'fas fa-tachometer-alt',
text: i18n.locale.dashboard, text: i18n.ts.dashboard,
to: '/admin/overview', to: '/admin/overview',
active: page.value === 'overview', active: page.value === 'overview',
}, { }, {
icon: 'fas fa-users', icon: 'fas fa-users',
text: i18n.locale.users, text: i18n.ts.users,
to: '/admin/users', to: '/admin/users',
active: page.value === 'users', active: page.value === 'users',
}, { }, {
icon: 'fas fa-laugh', icon: 'fas fa-laugh',
text: i18n.locale.customEmojis, text: i18n.ts.customEmojis,
to: '/admin/emojis', to: '/admin/emojis',
active: page.value === 'emojis', active: page.value === 'emojis',
}, { }, {
icon: 'fas fa-globe', icon: 'fas fa-globe',
text: i18n.locale.federation, text: i18n.ts.federation,
to: '/admin/federation', to: '/admin/federation',
active: page.value === 'federation', active: page.value === 'federation',
}, { }, {
icon: 'fas fa-clipboard-list', icon: 'fas fa-clipboard-list',
text: i18n.locale.jobQueue, text: i18n.ts.jobQueue,
to: '/admin/queue', to: '/admin/queue',
active: page.value === 'queue', active: page.value === 'queue',
}, { }, {
icon: 'fas fa-cloud', icon: 'fas fa-cloud',
text: i18n.locale.files, text: i18n.ts.files,
to: '/admin/files', to: '/admin/files',
active: page.value === 'files', active: page.value === 'files',
}, { }, {
icon: 'fas fa-broadcast-tower', icon: 'fas fa-broadcast-tower',
text: i18n.locale.announcements, text: i18n.ts.announcements,
to: '/admin/announcements', to: '/admin/announcements',
active: page.value === 'announcements', active: page.value === 'announcements',
}, { }, {
icon: 'fas fa-audio-description', icon: 'fas fa-audio-description',
text: i18n.locale.ads, text: i18n.ts.ads,
to: '/admin/ads', to: '/admin/ads',
active: page.value === 'ads', active: page.value === 'ads',
}, { }, {
icon: 'fas fa-exclamation-circle', icon: 'fas fa-exclamation-circle',
text: i18n.locale.abuseReports, text: i18n.ts.abuseReports,
to: '/admin/abuses', to: '/admin/abuses',
active: page.value === 'abuses', active: page.value === 'abuses',
}], }],
}, { }, {
title: i18n.locale.settings, title: i18n.ts.settings,
items: [{ items: [{
icon: 'fas fa-cog', icon: 'fas fa-cog',
text: i18n.locale.general, text: i18n.ts.general,
to: '/admin/settings', to: '/admin/settings',
active: page.value === 'settings', active: page.value === 'settings',
}, { }, {
icon: 'fas fa-envelope', icon: 'fas fa-envelope',
text: i18n.locale.emailServer, text: i18n.ts.emailServer,
to: '/admin/email-settings', to: '/admin/email-settings',
active: page.value === 'email-settings', active: page.value === 'email-settings',
}, { }, {
icon: 'fas fa-cloud', icon: 'fas fa-cloud',
text: i18n.locale.objectStorage, text: i18n.ts.objectStorage,
to: '/admin/object-storage', to: '/admin/object-storage',
active: page.value === 'object-storage', active: page.value === 'object-storage',
}, { }, {
icon: 'fas fa-lock', icon: 'fas fa-lock',
text: i18n.locale.security, text: i18n.ts.security,
to: '/admin/security', to: '/admin/security',
active: page.value === 'security', active: page.value === 'security',
}, { }, {
icon: 'fas fa-globe', icon: 'fas fa-globe',
text: i18n.locale.relays, text: i18n.ts.relays,
to: '/admin/relays', to: '/admin/relays',
active: page.value === 'relays', active: page.value === 'relays',
}, { }, {
icon: 'fas fa-share-alt', icon: 'fas fa-share-alt',
text: i18n.locale.integration, text: i18n.ts.integration,
to: '/admin/integrations', to: '/admin/integrations',
active: page.value === 'integrations', active: page.value === 'integrations',
}, { }, {
icon: 'fas fa-ban', icon: 'fas fa-ban',
text: i18n.locale.instanceBlocking, text: i18n.ts.instanceBlocking,
to: '/admin/instance-block', to: '/admin/instance-block',
active: page.value === 'instance-block', active: page.value === 'instance-block',
}, { }, {
icon: 'fas fa-ghost', icon: 'fas fa-ghost',
text: i18n.locale.proxyAccount, text: i18n.ts.proxyAccount,
to: '/admin/proxy-account', to: '/admin/proxy-account',
active: page.value === 'proxy-account', active: page.value === 'proxy-account',
}, { }, {
icon: 'fas fa-cogs', icon: 'fas fa-cogs',
text: i18n.locale.other, text: i18n.ts.other,
to: '/admin/other-settings', to: '/admin/other-settings',
active: page.value === 'other-settings', active: page.value === 'other-settings',
}], }],
}, { }, {
title: i18n.locale.info, title: i18n.ts.info,
items: [{ items: [{
icon: 'fas fa-database', icon: 'fas fa-database',
text: i18n.locale.database, text: i18n.ts.database,
to: '/admin/database', to: '/admin/database',
active: page.value === 'database', active: page.value === 'database',
}], }],
@ -275,37 +275,37 @@ export default defineComponent({
const lookup = (ev) => { const lookup = (ev) => {
os.popupMenu([{ os.popupMenu([{
text: i18n.locale.user, text: i18n.ts.user,
icon: 'fas fa-user', icon: 'fas fa-user',
action: () => { action: () => {
lookupUser(); lookupUser();
} }
}, { }, {
text: i18n.locale.note, text: i18n.ts.note,
icon: 'fas fa-pencil-alt', icon: 'fas fa-pencil-alt',
action: () => { action: () => {
alert('TODO'); alert('TODO');
} }
}, { }, {
text: i18n.locale.file, text: i18n.ts.file,
icon: 'fas fa-cloud', icon: 'fas fa-cloud',
action: () => { action: () => {
alert('TODO'); alert('TODO');
} }
}, { }, {
text: i18n.locale.instance, text: i18n.ts.instance,
icon: 'fas fa-globe', icon: 'fas fa-globe',
action: () => { action: () => {
alert('TODO'); alert('TODO');
} }
}], ev.currentTarget || ev.target); }], ev.currentTarget ?? ev.target);
}; };
return { return {
[symbols.PAGE_INFO]: INFO, [symbols.PAGE_INFO]: INFO,
menuDef, menuDef,
header: { header: {
title: i18n.locale.controlPanel, title: i18n.ts.controlPanel,
}, },
noMaintainerInformation, noMaintainerInformation,
noBotProtection, noBotProtection,

View File

@ -112,7 +112,7 @@ export default defineComponent({
}, },
setBannerImage(e) { setBannerImage(e) {
selectFile(e.currentTarget || e.target, null).then(file => { selectFile(e.currentTarget ?? e.target, null).then(file => {
this.bannerId = file.id; this.bannerId = file.id;
}); });
}, },

View File

@ -127,7 +127,7 @@ export default defineComponent({
clipId: this.clip.id, clipId: this.clip.id,
}); });
} }
} : undefined], ev.currentTarget || ev.target); } : undefined], ev.currentTarget ?? ev.target);
} }
} }
}); });

View File

@ -15,7 +15,7 @@ let folder = $ref(null);
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: computed(() => ({ [symbols.PAGE_INFO]: computed(() => ({
title: folder ? folder.name : i18n.locale.drive, title: folder ? folder.name : i18n.ts.drive,
icon: 'fas fa-cloud', icon: 'fas fa-cloud',
bg: 'var(--bg)', bg: 'var(--bg)',
hideHeader: true, hideHeader: true,

View File

@ -23,13 +23,13 @@ function menu(ev) {
type: 'label', type: 'label',
text: ':' + props.emoji.name + ':', text: ':' + props.emoji.name + ':',
}, { }, {
text: i18n.locale.copy, text: i18n.ts.copy,
icon: 'fas fa-copy', icon: 'fas fa-copy',
action: () => { action: () => {
copyToClipboard(`:${props.emoji.name}:`); copyToClipboard(`:${props.emoji.name}:`);
os.success(); os.success();
} }
}], ev.currentTarget || ev.target); }], ev.currentTarget ?? ev.target);
} }
</script> </script>

View File

@ -16,14 +16,14 @@ const tab = ref('category');
function menu(ev) { function menu(ev) {
os.popupMenu([{ os.popupMenu([{
icon: 'fas fa-download', icon: 'fas fa-download',
text: i18n.locale.export, text: i18n.ts.export,
action: async () => { action: async () => {
os.api('export-custom-emojis', { os.api('export-custom-emojis', {
}) })
.then(() => { .then(() => {
os.alert({ os.alert({
type: 'info', type: 'info',
text: i18n.locale.exportRequested, text: i18n.ts.exportRequested,
}); });
}).catch((e) => { }).catch((e) => {
os.alert({ os.alert({
@ -32,12 +32,12 @@ function menu(ev) {
}); });
}); });
} }
}], ev.currentTarget || ev.target); }], ev.currentTarget ?? ev.target);
} }
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.customEmojis, title: i18n.ts.customEmojis,
icon: 'fas fa-laugh', icon: 'fas fa-laugh',
bg: 'var(--bg)', bg: 'var(--bg)',
actions: [{ actions: [{

View File

@ -34,7 +34,7 @@ const pagingComponent = ref<InstanceType<typeof MkPagination>>();
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.favorites, title: i18n.ts.favorites,
icon: 'fas fa-star', icon: 'fas fa-star',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },

View File

@ -17,7 +17,7 @@ const pagination = {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.featured, title: i18n.ts.featured,
icon: 'fas fa-fire-alt', icon: 'fas fa-fire-alt',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },

View File

@ -135,7 +135,7 @@ function getStatus(instance) {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.federation, title: i18n.ts.federation,
icon: 'fas fa-globe', icon: 'fas fa-globe',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },

View File

@ -60,7 +60,7 @@ function reject(user) {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: computed(() => ({ [symbols.PAGE_INFO]: computed(() => ({
title: i18n.locale.followRequests, title: i18n.ts.followRequests,
icon: 'fas fa-user-clock', icon: 'fas fa-user-clock',
bg: 'var(--bg)', bg: 'var(--bg)',
})), })),

View File

@ -92,7 +92,7 @@ export default defineComponent({
methods: { methods: {
selectFile(e) { selectFile(e) {
selectFiles(e.currentTarget || e.target, null).then(files => { selectFiles(e.currentTarget ?? e.target, null).then(files => {
this.files = this.files.concat(files); this.files = this.files.concat(files);
}); });
}, },

View File

@ -16,7 +16,7 @@ const pagination = {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.mentions, title: i18n.ts.mentions,
icon: 'fas fa-at', icon: 'fas fa-at',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },

View File

@ -12,14 +12,14 @@ import { i18n } from '@/i18n';
const pagination = { const pagination = {
endpoint: 'notes/mentions' as const, endpoint: 'notes/mentions' as const,
limit: 10, limit: 10,
params: () => ({ params: {
visibility: 'specified' visibility: 'specified'
}), },
}; };
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.directNotes, title: i18n.ts.directNotes,
icon: 'fas fa-envelope', icon: 'fas fa-envelope',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },

View File

@ -128,7 +128,7 @@ export default defineComponent({
text: this.$ts.messagingWithGroup, text: this.$ts.messagingWithGroup,
icon: 'fas fa-users', icon: 'fas fa-users',
action: () => { this.startGroup() } action: () => { this.startGroup() }
}], ev.currentTarget || ev.target); }], ev.currentTarget ?? ev.target);
}, },
async startUser() { async startUser() {

View File

@ -133,7 +133,7 @@ function onCompositionUpdate() {
} }
function chooseFile(e: MouseEvent) { function chooseFile(e: MouseEvent) {
selectFile(e.currentTarget || e.target, i18n.locale.selectFile).then(selectedFile => { selectFile(e.currentTarget ?? e.target, i18n.locale.selectFile).then(selectedFile => {
file = selectedFile; file = selectedFile;
}); });
} }
@ -193,7 +193,7 @@ function deleteDraft() {
} }
async function insertEmoji(ev: MouseEvent) { async function insertEmoji(ev: MouseEvent) {
os.openEmojiPicker(ev.currentTarget || ev.target, {}, textEl); os.openEmojiPicker(ev.currentTarget ?? ev.target, {}, textEl);
} }
onMounted(() => { onMounted(() => {

View File

@ -31,7 +31,7 @@ function onAntennaCreated() {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.manageAntennas, title: i18n.ts.manageAntennas,
icon: 'fas fa-satellite', icon: 'fas fa-satellite',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },

View File

@ -29,20 +29,20 @@ const pagination = {
const pagingComponent = $ref<InstanceType<typeof MkPagination>>(); const pagingComponent = $ref<InstanceType<typeof MkPagination>>();
async function create() { async function create() {
const { canceled, result } = await os.form(i18n.locale.createNewClip, { const { canceled, result } = await os.form(i18n.ts.createNewClip, {
name: { name: {
type: 'string', type: 'string',
label: i18n.locale.name, label: i18n.ts.name,
}, },
description: { description: {
type: 'string', type: 'string',
required: false, required: false,
multiline: true, multiline: true,
label: i18n.locale.description, label: i18n.ts.description,
}, },
isPublic: { isPublic: {
type: 'boolean', type: 'boolean',
label: i18n.locale.public, label: i18n.ts.public,
default: false, default: false,
}, },
}); });
@ -63,7 +63,7 @@ function onClipDeleted() {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.clip, title: i18n.ts.clip,
icon: 'fas fa-paperclip', icon: 'fas fa-paperclip',
bg: 'var(--bg)', bg: 'var(--bg)',
action: { action: {

View File

@ -31,7 +31,7 @@ const pagination = {
async function create() { async function create() {
const { canceled, result: name } = await os.inputText({ const { canceled, result: name } = await os.inputText({
title: i18n.locale.enterListName, title: i18n.ts.enterListName,
}); });
if (canceled) return; if (canceled) return;
await os.apiWithDialog('users/lists/create', { name: name }); await os.apiWithDialog('users/lists/create', { name: name });
@ -40,7 +40,7 @@ async function create() {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.manageLists, title: i18n.ts.manageLists,
icon: 'fas fa-list-ul', icon: 'fas fa-list-ul',
bg: 'var(--bg)', bg: 'var(--bg)',
action: { action: {

View File

@ -13,7 +13,7 @@ import { i18n } from '@/i18n';
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.notFound, title: i18n.ts.notFound,
icon: 'fas fa-exclamation-triangle', icon: 'fas fa-exclamation-triangle',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },

View File

@ -27,26 +27,26 @@ function setFilter(ev) {
})); }));
const items = includeTypes != null ? [{ const items = includeTypes != null ? [{
icon: 'fas fa-times', icon: 'fas fa-times',
text: i18n.locale.clear, text: i18n.ts.clear,
action: () => { action: () => {
includeTypes = null; includeTypes = null;
} }
}, null, ...typeItems] : typeItems; }, null, ...typeItems] : typeItems;
os.popupMenu(items, ev.currentTarget || ev.target); os.popupMenu(items, ev.currentTarget ?? ev.target);
} }
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: computed(() => ({ [symbols.PAGE_INFO]: computed(() => ({
title: i18n.locale.notifications, title: i18n.ts.notifications,
icon: 'fas fa-bell', icon: 'fas fa-bell',
bg: 'var(--bg)', bg: 'var(--bg)',
actions: [{ actions: [{
text: i18n.locale.filter, text: i18n.ts.filter,
icon: 'fas fa-filter', icon: 'fas fa-filter',
highlighted: includeTypes != null, highlighted: includeTypes != null,
handler: setFilter, handler: setFilter,
}, { }, {
text: i18n.locale.markAllAsRead, text: i18n.ts.markAllAsRead,
icon: 'fas fa-check', icon: 'fas fa-check',
handler: () => { handler: () => {
os.apiWithDialog('notifications/mark-all-as-read'); os.apiWithDialog('notifications/mark-all-as-read');
@ -54,11 +54,11 @@ defineExpose({
}], }],
tabs: [{ tabs: [{
active: tab === 'all', active: tab === 'all',
title: i18n.locale.all, title: i18n.ts.all,
onClick: () => { tab = 'all'; }, onClick: () => { tab = 'all'; },
}, { }, {
active: tab === 'unread', active: tab === 'unread',
title: i18n.locale.unread, title: i18n.ts.unread,
onClick: () => { tab = 'unread'; }, onClick: () => { tab = 'unread'; },
},] },]
})), })),

View File

@ -448,7 +448,7 @@ export default defineComponent({
}, },
setEyeCatchingImage(e) { setEyeCatchingImage(e) {
selectFile(e.currentTarget || e.target, null).then(file => { selectFile(e.currentTarget ?? e.target, null).then(file => {
this.eyeCatchingImageId = file.id; this.eyeCatchingImageId = file.id;
}); });
}, },

View File

@ -12,7 +12,7 @@ import { i18n } from '@/i18n';
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: computed(() => ({ [symbols.PAGE_INFO]: computed(() => ({
title: i18n.locale.preview, title: i18n.ts.preview,
icon: 'fas fa-eye', icon: 'fas fa-eye',
bg: 'var(--bg)', bg: 'var(--bg)',
})), })),

View File

@ -3,10 +3,10 @@
<div class="_formRoot"> <div class="_formRoot">
<FormInput v-model="password" type="password" class="_formBlock"> <FormInput v-model="password" type="password" class="_formBlock">
<template #prefix><i class="fas fa-lock"></i></template> <template #prefix><i class="fas fa-lock"></i></template>
<template #label>{{ i18n.locale.newPassword }}</template> <template #label>{{ i18n.ts.newPassword }}</template>
</FormInput> </FormInput>
<FormButton primary class="_formBlock" @click="save">{{ i18n.locale.save }}</FormButton> <FormButton primary class="_formBlock" @click="save">{{ i18n.ts.save }}</FormButton>
</div> </div>
</MkSpacer> </MkSpacer>
</template> </template>
@ -43,7 +43,7 @@ onMounted(() => {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.resetPassword, title: i18n.ts.resetPassword,
icon: 'fas fa-lock', icon: 'fas fa-lock',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },

View File

@ -64,7 +64,7 @@ export default defineComponent({
icon: 'fas fa-trash-alt', icon: 'fas fa-trash-alt',
danger: true, danger: true,
action: () => this.removeAccount(account), action: () => this.removeAccount(account),
}], ev.currentTarget || ev.target); }], ev.currentTarget ?? ev.target);
}, },
addAccount(ev) { addAccount(ev) {
@ -74,7 +74,7 @@ export default defineComponent({
}, { }, {
text: this.$ts.createAccount, text: this.$ts.createAccount,
action: () => { this.createAccount(); }, action: () => { this.createAccount(); },
}], ev.currentTarget || ev.target); }], ev.currentTarget ?? ev.target);
}, },
addExistingAccount() { addExistingAccount() {

View File

@ -62,7 +62,7 @@ export default defineComponent({
const emailAddress = ref($i.email); const emailAddress = ref($i.email);
const INFO = { const INFO = {
title: i18n.locale.email, title: i18n.ts.email,
icon: 'fas fa-envelope', icon: 'fas fa-envelope',
bg: 'var(--bg)', bg: 'var(--bg)',
}; };
@ -75,7 +75,7 @@ export default defineComponent({
const saveEmailAddress = () => { const saveEmailAddress = () => {
os.inputText({ os.inputText({
title: i18n.locale.password, title: i18n.ts.password,
type: 'password' type: 'password'
}).then(({ canceled, result: password }) => { }).then(({ canceled, result: password }) => {
if (canceled) return; if (canceled) return;

View File

@ -60,7 +60,7 @@ export default defineComponent({
setup(props, context) { setup(props, context) {
const INFO = { const INFO = {
title: i18n.locale.importAndExport, title: i18n.ts.importAndExport,
icon: 'fas fa-boxes', icon: 'fas fa-boxes',
bg: 'var(--bg)', bg: 'var(--bg)',
}; };
@ -71,14 +71,14 @@ export default defineComponent({
const onExportSuccess = () => { const onExportSuccess = () => {
os.alert({ os.alert({
type: 'info', type: 'info',
text: i18n.locale.exportRequested, text: i18n.ts.exportRequested,
}); });
}; };
const onImportSuccess = () => { const onImportSuccess = () => {
os.alert({ os.alert({
type: 'info', type: 'info',
text: i18n.locale.importRequested, text: i18n.ts.importRequested,
}); });
}; };
@ -114,22 +114,22 @@ export default defineComponent({
}; };
const importFollowing = async (ev) => { const importFollowing = async (ev) => {
const file = await selectFile(ev.currentTarget || ev.target); const file = await selectFile(ev.currentTarget ?? ev.target);
os.api('i/import-following', { fileId: file.id }).then(onImportSuccess).catch(onError); os.api('i/import-following', { fileId: file.id }).then(onImportSuccess).catch(onError);
}; };
const importUserLists = async (ev) => { const importUserLists = async (ev) => {
const file = await selectFile(ev.currentTarget || ev.target); const file = await selectFile(ev.currentTarget ?? ev.target);
os.api('i/import-user-lists', { fileId: file.id }).then(onImportSuccess).catch(onError); os.api('i/import-user-lists', { fileId: file.id }).then(onImportSuccess).catch(onError);
}; };
const importMuting = async (ev) => { const importMuting = async (ev) => {
const file = await selectFile(ev.currentTarget || ev.target); const file = await selectFile(ev.currentTarget ?? ev.target);
os.api('i/import-muting', { fileId: file.id }).then(onImportSuccess).catch(onError); os.api('i/import-muting', { fileId: file.id }).then(onImportSuccess).catch(onError);
}; };
const importBlocking = async (ev) => { const importBlocking = async (ev) => {
const file = await selectFile(ev.currentTarget || ev.target); const file = await selectFile(ev.currentTarget ?? ev.target);
os.api('i/import-blocking', { fileId: file.id }).then(onImportSuccess).catch(onError); os.api('i/import-blocking', { fileId: file.id }).then(onImportSuccess).catch(onError);
}; };

View File

@ -49,7 +49,7 @@ export default defineComponent({
setup(props, context) { setup(props, context) {
const indexInfo = { const indexInfo = {
title: i18n.locale.settings, title: i18n.ts.settings,
icon: 'fas fa-cog', icon: 'fas fa-cog',
bg: 'var(--bg)', bg: 'var(--bg)',
hideHeader: true, hideHeader: true,
@ -61,96 +61,96 @@ export default defineComponent({
const el = ref(null); const el = ref(null);
const childInfo = ref(null); const childInfo = ref(null);
const menuDef = computed(() => [{ const menuDef = computed(() => [{
title: i18n.locale.basicSettings, title: i18n.ts.basicSettings,
items: [{ items: [{
icon: 'fas fa-user', icon: 'fas fa-user',
text: i18n.locale.profile, text: i18n.ts.profile,
to: '/settings/profile', to: '/settings/profile',
active: page.value === 'profile', active: page.value === 'profile',
}, { }, {
icon: 'fas fa-lock-open', icon: 'fas fa-lock-open',
text: i18n.locale.privacy, text: i18n.ts.privacy,
to: '/settings/privacy', to: '/settings/privacy',
active: page.value === 'privacy', active: page.value === 'privacy',
}, { }, {
icon: 'fas fa-laugh', icon: 'fas fa-laugh',
text: i18n.locale.reaction, text: i18n.ts.reaction,
to: '/settings/reaction', to: '/settings/reaction',
active: page.value === 'reaction', active: page.value === 'reaction',
}, { }, {
icon: 'fas fa-cloud', icon: 'fas fa-cloud',
text: i18n.locale.drive, text: i18n.ts.drive,
to: '/settings/drive', to: '/settings/drive',
active: page.value === 'drive', active: page.value === 'drive',
}, { }, {
icon: 'fas fa-bell', icon: 'fas fa-bell',
text: i18n.locale.notifications, text: i18n.ts.notifications,
to: '/settings/notifications', to: '/settings/notifications',
active: page.value === 'notifications', active: page.value === 'notifications',
}, { }, {
icon: 'fas fa-envelope', icon: 'fas fa-envelope',
text: i18n.locale.email, text: i18n.ts.email,
to: '/settings/email', to: '/settings/email',
active: page.value === 'email', active: page.value === 'email',
}, { }, {
icon: 'fas fa-share-alt', icon: 'fas fa-share-alt',
text: i18n.locale.integration, text: i18n.ts.integration,
to: '/settings/integration', to: '/settings/integration',
active: page.value === 'integration', active: page.value === 'integration',
}, { }, {
icon: 'fas fa-lock', icon: 'fas fa-lock',
text: i18n.locale.security, text: i18n.ts.security,
to: '/settings/security', to: '/settings/security',
active: page.value === 'security', active: page.value === 'security',
}], }],
}, { }, {
title: i18n.locale.clientSettings, title: i18n.ts.clientSettings,
items: [{ items: [{
icon: 'fas fa-cogs', icon: 'fas fa-cogs',
text: i18n.locale.general, text: i18n.ts.general,
to: '/settings/general', to: '/settings/general',
active: page.value === 'general', active: page.value === 'general',
}, { }, {
icon: 'fas fa-palette', icon: 'fas fa-palette',
text: i18n.locale.theme, text: i18n.ts.theme,
to: '/settings/theme', to: '/settings/theme',
active: page.value === 'theme', active: page.value === 'theme',
}, { }, {
icon: 'fas fa-list-ul', icon: 'fas fa-list-ul',
text: i18n.locale.menu, text: i18n.ts.menu,
to: '/settings/menu', to: '/settings/menu',
active: page.value === 'menu', active: page.value === 'menu',
}, { }, {
icon: 'fas fa-music', icon: 'fas fa-music',
text: i18n.locale.sounds, text: i18n.ts.sounds,
to: '/settings/sounds', to: '/settings/sounds',
active: page.value === 'sounds', active: page.value === 'sounds',
}, { }, {
icon: 'fas fa-plug', icon: 'fas fa-plug',
text: i18n.locale.plugins, text: i18n.ts.plugins,
to: '/settings/plugin', to: '/settings/plugin',
active: page.value === 'plugin', active: page.value === 'plugin',
}], }],
}, { }, {
title: i18n.locale.otherSettings, title: i18n.ts.otherSettings,
items: [{ items: [{
icon: 'fas fa-boxes', icon: 'fas fa-boxes',
text: i18n.locale.importAndExport, text: i18n.ts.importAndExport,
to: '/settings/import-export', to: '/settings/import-export',
active: page.value === 'import-export', active: page.value === 'import-export',
}, { }, {
icon: 'fas fa-volume-mute', icon: 'fas fa-volume-mute',
text: i18n.locale.instanceMute, text: i18n.ts.instanceMute,
to: '/settings/instance-mute', to: '/settings/instance-mute',
active: page.value === 'instance-mute', active: page.value === 'instance-mute',
}, { }, {
icon: 'fas fa-ban', icon: 'fas fa-ban',
text: i18n.locale.muteAndBlock, text: i18n.ts.muteAndBlock,
to: '/settings/mute-block', to: '/settings/mute-block',
active: page.value === 'mute-block', active: page.value === 'mute-block',
}, { }, {
icon: 'fas fa-comment-slash', icon: 'fas fa-comment-slash',
text: i18n.locale.wordMute, text: i18n.ts.wordMute,
to: '/settings/word-mute', to: '/settings/word-mute',
active: page.value === 'word-mute', active: page.value === 'word-mute',
}, { }, {
@ -160,7 +160,7 @@ export default defineComponent({
active: page.value === 'api', active: page.value === 'api',
}, { }, {
icon: 'fas fa-ellipsis-h', icon: 'fas fa-ellipsis-h',
text: i18n.locale.other, text: i18n.ts.other,
to: '/settings/other', to: '/settings/other',
active: page.value === 'other', active: page.value === 'other',
}], }],
@ -168,7 +168,7 @@ export default defineComponent({
items: [{ items: [{
type: 'button', type: 'button',
icon: 'fas fa-trash', icon: 'fas fa-trash',
text: i18n.locale.clearCache, text: i18n.ts.clearCache,
action: () => { action: () => {
localStorage.removeItem('locale'); localStorage.removeItem('locale');
localStorage.removeItem('theme'); localStorage.removeItem('theme');
@ -177,7 +177,7 @@ export default defineComponent({
}, { }, {
type: 'button', type: 'button',
icon: 'fas fa-sign-in-alt fa-flip-horizontal', icon: 'fas fa-sign-in-alt fa-flip-horizontal',
text: i18n.locale.logout, text: i18n.ts.logout,
action: () => { action: () => {
signout(); signout();
}, },

View File

@ -52,7 +52,7 @@ const blockingPagination = {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.muteAndBlock, title: i18n.ts.muteAndBlock,
icon: 'fas fa-ban', icon: 'fas fa-ban',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },

View File

@ -86,7 +86,7 @@ function save() {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.privacy, title: i18n.ts.privacy,
icon: 'fas fa-lock-open', icon: 'fas fa-lock-open',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },

View File

@ -3,45 +3,45 @@
<div class="llvierxe" :style="{ backgroundImage: $i.bannerUrl ? `url(${ $i.bannerUrl })` : null }"> <div class="llvierxe" :style="{ backgroundImage: $i.bannerUrl ? `url(${ $i.bannerUrl })` : null }">
<div class="avatar _acrylic"> <div class="avatar _acrylic">
<MkAvatar class="avatar" :user="$i" :disable-link="true" @click="changeAvatar"/> <MkAvatar class="avatar" :user="$i" :disable-link="true" @click="changeAvatar"/>
<MkButton primary class="avatarEdit" @click="changeAvatar">{{ i18n.locale._profile.changeAvatar }}</MkButton> <MkButton primary class="avatarEdit" @click="changeAvatar">{{ i18n.ts._profile.changeAvatar }}</MkButton>
</div> </div>
<MkButton primary class="bannerEdit" @click="changeBanner">{{ i18n.locale._profile.changeBanner }}</MkButton> <MkButton primary class="bannerEdit" @click="changeBanner">{{ i18n.ts._profile.changeBanner }}</MkButton>
</div> </div>
<FormInput v-model="profile.name" :max="30" manual-save class="_formBlock"> <FormInput v-model="profile.name" :max="30" manual-save class="_formBlock">
<template #label>{{ i18n.locale._profile.name }}</template> <template #label>{{ i18n.ts._profile.name }}</template>
</FormInput> </FormInput>
<FormTextarea v-model="profile.description" :max="500" tall manual-save class="_formBlock"> <FormTextarea v-model="profile.description" :max="500" tall manual-save class="_formBlock">
<template #label>{{ i18n.locale._profile.description }}</template> <template #label>{{ i18n.ts._profile.description }}</template>
<template #caption>{{ i18n.locale._profile.youCanIncludeHashtags }}</template> <template #caption>{{ i18n.ts._profile.youCanIncludeHashtags }}</template>
</FormTextarea> </FormTextarea>
<FormInput v-model="profile.location" manual-save class="_formBlock"> <FormInput v-model="profile.location" manual-save class="_formBlock">
<template #label>{{ i18n.locale.location }}</template> <template #label>{{ i18n.ts.location }}</template>
<template #prefix><i class="fas fa-map-marker-alt"></i></template> <template #prefix><i class="fas fa-map-marker-alt"></i></template>
</FormInput> </FormInput>
<FormInput v-model="profile.birthday" type="date" manual-save class="_formBlock"> <FormInput v-model="profile.birthday" type="date" manual-save class="_formBlock">
<template #label>{{ i18n.locale.birthday }}</template> <template #label>{{ i18n.ts.birthday }}</template>
<template #prefix><i class="fas fa-birthday-cake"></i></template> <template #prefix><i class="fas fa-birthday-cake"></i></template>
</FormInput> </FormInput>
<FormSelect v-model="profile.lang" class="_formBlock"> <FormSelect v-model="profile.lang" class="_formBlock">
<template #label>{{ i18n.locale.language }}</template> <template #label>{{ i18n.ts.language }}</template>
<option v-for="x in langs" :key="x[0]" :value="x[0]">{{ x[1] }}</option> <option v-for="x in langs" :key="x[0]" :value="x[0]">{{ x[1] }}</option>
</FormSelect> </FormSelect>
<FormSlot> <FormSlot>
<MkButton @click="editMetadata">{{ i18n.locale._profile.metadataEdit }}</MkButton> <MkButton @click="editMetadata">{{ i18n.ts._profile.metadataEdit }}</MkButton>
<template #caption>{{ i18n.locale._profile.metadataDescription }}</template> <template #caption>{{ i18n.ts._profile.metadataDescription }}</template>
</FormSlot> </FormSlot>
<FormSwitch v-model="profile.isCat" class="_formBlock">{{ i18n.locale.flagAsCat }}<template #caption>{{ i18n.locale.flagAsCatDescription }}</template></FormSwitch> <FormSwitch v-model="profile.isCat" class="_formBlock">{{ i18n.ts.flagAsCat }}<template #caption>{{ i18n.ts.flagAsCatDescription }}</template></FormSwitch>
<FormSwitch v-model="profile.isBot" class="_formBlock">{{ i18n.locale.flagAsBot }}<template #caption>{{ i18n.locale.flagAsBotDescription }}</template></FormSwitch> <FormSwitch v-model="profile.isBot" class="_formBlock">{{ i18n.ts.flagAsBot }}<template #caption>{{ i18n.ts.flagAsBotDescription }}</template></FormSwitch>
<FormSwitch v-model="profile.alwaysMarkNsfw" class="_formBlock">{{ i18n.locale.alwaysMarkSensitive }}</FormSwitch> <FormSwitch v-model="profile.alwaysMarkNsfw" class="_formBlock">{{ i18n.ts.alwaysMarkSensitive }}</FormSwitch>
</div> </div>
</template> </template>
@ -102,7 +102,7 @@ function save() {
} }
function changeAvatar(ev) { function changeAvatar(ev) {
selectFile(ev.currentTarget || ev.target, i18n.locale.avatar).then(async (file) => { selectFile(ev.currentTarget ?? ev.target, i18n.ts.avatar).then(async (file) => {
const i = await os.apiWithDialog('i/update', { const i = await os.apiWithDialog('i/update', {
avatarId: file.id, avatarId: file.id,
}); });
@ -112,7 +112,7 @@ function changeAvatar(ev) {
} }
function changeBanner(ev) { function changeBanner(ev) {
selectFile(ev.currentTarget || ev.target, i18n.locale.banner).then(async (file) => { selectFile(ev.currentTarget ?? ev.target, i18n.ts.banner).then(async (file) => {
const i = await os.apiWithDialog('i/update', { const i = await os.apiWithDialog('i/update', {
bannerId: file.id, bannerId: file.id,
}); });
@ -122,45 +122,45 @@ function changeBanner(ev) {
} }
async function editMetadata() { async function editMetadata() {
const { canceled, result } = await os.form(i18n.locale._profile.metadata, { const { canceled, result } = await os.form(i18n.ts._profile.metadata, {
fieldName0: { fieldName0: {
type: 'string', type: 'string',
label: i18n.locale._profile.metadataLabel + ' 1', label: i18n.ts._profile.metadataLabel + ' 1',
default: additionalFields.fieldName0, default: additionalFields.fieldName0,
}, },
fieldValue0: { fieldValue0: {
type: 'string', type: 'string',
label: i18n.locale._profile.metadataContent + ' 1', label: i18n.ts._profile.metadataContent + ' 1',
default: additionalFields.fieldValue0, default: additionalFields.fieldValue0,
}, },
fieldName1: { fieldName1: {
type: 'string', type: 'string',
label: i18n.locale._profile.metadataLabel + ' 2', label: i18n.ts._profile.metadataLabel + ' 2',
default: additionalFields.fieldName1, default: additionalFields.fieldName1,
}, },
fieldValue1: { fieldValue1: {
type: 'string', type: 'string',
label: i18n.locale._profile.metadataContent + ' 2', label: i18n.ts._profile.metadataContent + ' 2',
default: additionalFields.fieldValue1, default: additionalFields.fieldValue1,
}, },
fieldName2: { fieldName2: {
type: 'string', type: 'string',
label: i18n.locale._profile.metadataLabel + ' 3', label: i18n.ts._profile.metadataLabel + ' 3',
default: additionalFields.fieldName2, default: additionalFields.fieldName2,
}, },
fieldValue2: { fieldValue2: {
type: 'string', type: 'string',
label: i18n.locale._profile.metadataContent + ' 3', label: i18n.ts._profile.metadataContent + ' 3',
default: additionalFields.fieldValue2, default: additionalFields.fieldValue2,
}, },
fieldName3: { fieldName3: {
type: 'string', type: 'string',
label: i18n.locale._profile.metadataLabel + ' 4', label: i18n.ts._profile.metadataLabel + ' 4',
default: additionalFields.fieldName3, default: additionalFields.fieldName3,
}, },
fieldValue3: { fieldValue3: {
type: 'string', type: 'string',
label: i18n.locale._profile.metadataContent + ' 4', label: i18n.ts._profile.metadataContent + ' 4',
default: additionalFields.fieldValue3, default: additionalFields.fieldValue3,
}, },
}); });
@ -196,7 +196,7 @@ async function editMetadata() {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.profile, title: i18n.ts.profile,
icon: 'fas fa-user', icon: 'fas fa-user',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },

View File

@ -44,8 +44,8 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent } from 'vue'; import { watch } from 'vue';
import XDraggable from 'vuedraggable'; import XDraggable from 'vuedraggable';
import FormInput from '@/components/form/input.vue'; import FormInput from '@/components/form/input.vue';
import FormRadios from '@/components/form/radios.vue'; import FormRadios from '@/components/form/radios.vue';
@ -56,91 +56,70 @@ import FormSwitch from '@/components/form/switch.vue';
import * as os from '@/os'; import * as os from '@/os';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import * as symbols from '@/symbols'; import * as symbols from '@/symbols';
import { i18n } from '@/i18n';
export default defineComponent({ let reactions = $ref(JSON.parse(JSON.stringify(defaultStore.state.reactions)));
components: {
FormInput,
FormButton,
FromSlot,
FormRadios,
FormSection,
FormSwitch,
XDraggable,
},
emits: ['info'], const reactionPickerWidth = $computed(defaultStore.makeGetterSetter('reactionPickerWidth'));
const reactionPickerHeight = $computed(defaultStore.makeGetterSetter('reactionPickerHeight'));
data() { const reactionPickerUseDrawerForMobile = $computed(defaultStore.makeGetterSetter('reactionPickerUseDrawerForMobile'));
return {
[symbols.PAGE_INFO]: { function save() {
title: this.$ts.reaction, defaultStore.set('reactions', reactions);
icon: 'fas fa-laugh', }
action: {
icon: 'fas fa-eye', function remove(reaction, ev: MouseEvent) {
handler: this.preview os.popupMenu([{
}, text: i18n.ts.remove,
bg: 'var(--bg)', action: () => {
}, reactions = reactions.filter(x => x !== reaction);
reactions: JSON.parse(JSON.stringify(this.$store.state.reactions)),
} }
}, }], ev.currentTarget ?? ev.target);
}
computed: { function preview(ev: MouseEvent) {
reactionPickerWidth: defaultStore.makeGetterSetter('reactionPickerWidth'), os.popup(import('@/components/emoji-picker-dialog.vue'), {
reactionPickerHeight: defaultStore.makeGetterSetter('reactionPickerHeight'), asReactionPicker: true,
reactionPickerUseDrawerForMobile: defaultStore.makeGetterSetter('reactionPickerUseDrawerForMobile'), src: ev.currentTarget ?? ev.target,
}, }, {}, 'closed');
}
watch: { async function setDefault() {
reactions: { const { canceled } = await os.confirm({
handler() { type: 'warning',
this.save(); text: i18n.ts.resetAreYouSure,
}, });
deep: true if (canceled) return;
reactions = JSON.parse(JSON.stringify(defaultStore.def.reactions.default));
}
function chooseEmoji(ev: MouseEvent) {
os.pickEmoji(ev.currentTarget ?? ev.target, {
showPinned: false
}).then(emoji => {
if (!reactions.includes(emoji)) {
reactions.push(emoji);
} }
});
}
watch($$(reactions), () => {
save();
}, {
deep: true,
});
defineExpose({
[symbols.PAGE_INFO]: {
title: i18n.ts.reaction,
icon: 'fas fa-laugh',
action: {
icon: 'fas fa-eye',
handler: preview,
},
bg: 'var(--bg)',
}, },
methods: {
save() {
this.$store.set('reactions', this.reactions);
},
remove(reaction, ev) {
os.popupMenu([{
text: this.$ts.remove,
action: () => {
this.reactions = this.reactions.filter(x => x !== reaction)
}
}], ev.currentTarget || ev.target);
},
preview(ev) {
os.popup(import('@/components/emoji-picker-dialog.vue'), {
asReactionPicker: true,
src: ev.currentTarget || ev.target,
}, {}, 'closed');
},
async setDefault() {
const { canceled } = await os.confirm({
type: 'warning',
text: this.$ts.resetAreYouSure,
});
if (canceled) return;
this.reactions = JSON.parse(JSON.stringify(this.$store.def.reactions.default));
},
chooseEmoji(ev) {
os.pickEmoji(ev.currentTarget || ev.target, {
showPinned: false
}).then(emoji => {
if (!this.reactions.includes(emoji)) {
this.reactions.push(emoji);
}
});
}
}
}); });
</script> </script>

View File

@ -1,12 +1,12 @@
<template> <template>
<div class="_formRoot"> <div class="_formRoot">
<FormTextarea v-model="installThemeCode" class="_formBlock"> <FormTextarea v-model="installThemeCode" class="_formBlock">
<template #label>{{ i18n.locale._theme.code }}</template> <template #label>{{ i18n.ts._theme.code }}</template>
</FormTextarea> </FormTextarea>
<div class="_formBlock" style="display: flex; gap: var(--margin); flex-wrap: wrap;"> <div class="_formBlock" style="display: flex; gap: var(--margin); flex-wrap: wrap;">
<FormButton :disabled="installThemeCode == null" inline @click="() => preview(installThemeCode)"><i class="fas fa-eye"></i> {{ i18n.locale.preview }}</FormButton> <FormButton :disabled="installThemeCode == null" inline @click="() => preview(installThemeCode)"><i class="fas fa-eye"></i> {{ i18n.ts.preview }}</FormButton>
<FormButton :disabled="installThemeCode == null" primary inline @click="() => install(installThemeCode)"><i class="fas fa-check"></i> {{ i18n.locale.install }}</FormButton> <FormButton :disabled="installThemeCode == null" primary inline @click="() => install(installThemeCode)"><i class="fas fa-check"></i> {{ i18n.ts.install }}</FormButton>
</div> </div>
</div> </div>
</template> </template>
@ -32,21 +32,21 @@ function parseThemeCode(code: string) {
} catch (e) { } catch (e) {
os.alert({ os.alert({
type: 'error', type: 'error',
text: i18n.locale._theme.invalid text: i18n.ts._theme.invalid
}); });
return false; return false;
} }
if (!validateTheme(theme)) { if (!validateTheme(theme)) {
os.alert({ os.alert({
type: 'error', type: 'error',
text: i18n.locale._theme.invalid text: i18n.ts._theme.invalid
}); });
return false; return false;
} }
if (getThemes().some(t => t.id === theme.id)) { if (getThemes().some(t => t.id === theme.id)) {
os.alert({ os.alert({
type: 'info', type: 'info',
text: i18n.locale._theme.alreadyInstalled text: i18n.ts._theme.alreadyInstalled
}); });
return false; return false;
} }
@ -71,7 +71,7 @@ async function install(code: string): Promise<void> {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale._theme.install, title: i18n.ts._theme.install,
icon: 'fas fa-download', icon: 'fas fa-download',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },

View File

@ -116,7 +116,7 @@ export default defineComponent({
setup(props, { emit }) { setup(props, { emit }) {
const INFO = { const INFO = {
title: i18n.locale.theme, title: i18n.ts.theme,
icon: 'fas fa-palette', icon: 'fas fa-palette',
bg: 'var(--bg)', bg: 'var(--bg)',
}; };
@ -184,7 +184,7 @@ export default defineComponent({
themesCount, themesCount,
wallpaper, wallpaper,
setWallpaper(e) { setWallpaper(e) {
selectFile(e.currentTarget || e.target, null).then(file => { selectFile(e.currentTarget ?? e.target, null).then(file => {
wallpaper.value = file.url; wallpaper.value = file.url;
}); });
}, },

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
{{ i18n.locale.processing }} {{ i18n.ts.processing }}
</div> </div>
</template> </template>
@ -18,7 +18,7 @@ const props = defineProps<{
onMounted(async () => { onMounted(async () => {
await os.alert({ await os.alert({
type: 'info', type: 'info',
text: i18n.t('clickToFinishEmailVerification', { ok: i18n.locale.gotIt }), text: i18n.t('clickToFinishEmailVerification', { ok: i18n.ts.gotIt }),
}); });
const res = await os.apiWithDialog('signup-pending', { const res = await os.apiWithDialog('signup-pending', {
code: props.code, code: props.code,
@ -28,7 +28,7 @@ onMounted(async () => {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.signup, title: i18n.ts.signup,
icon: 'fas fa-user', icon: 'fas fa-user',
}, },
}); });

View File

@ -2,7 +2,7 @@
<MkSpacer :content-max="800" :margin-min="16" :margin-max="32"> <MkSpacer :content-max="800" :margin-min="16" :margin-max="32">
<div class="cwepdizn _formRoot"> <div class="cwepdizn _formRoot">
<FormFolder :default-open="true" class="_formBlock"> <FormFolder :default-open="true" class="_formBlock">
<template #label>{{ i18n.locale.backgroundColor }}</template> <template #label>{{ i18n.ts.backgroundColor }}</template>
<div class="cwepdizn-colors"> <div class="cwepdizn-colors">
<div class="row"> <div class="row">
<button v-for="color in bgColors.filter(x => x.kind === 'light')" :key="color.color" class="color _button" :class="{ active: theme.props.bg === color.color }" @click="setBgColor(color)"> <button v-for="color in bgColors.filter(x => x.kind === 'light')" :key="color.color" class="color _button" :class="{ active: theme.props.bg === color.color }" @click="setBgColor(color)">
@ -18,7 +18,7 @@
</FormFolder> </FormFolder>
<FormFolder :default-open="true" class="_formBlock"> <FormFolder :default-open="true" class="_formBlock">
<template #label>{{ i18n.locale.accentColor }}</template> <template #label>{{ i18n.ts.accentColor }}</template>
<div class="cwepdizn-colors"> <div class="cwepdizn-colors">
<div class="row"> <div class="row">
<button v-for="color in accentColors" :key="color" class="color rounded _button" :class="{ active: theme.props.accent === color }" @click="setAccentColor(color)"> <button v-for="color in accentColors" :key="color" class="color rounded _button" :class="{ active: theme.props.accent === color }" @click="setAccentColor(color)">
@ -29,7 +29,7 @@
</FormFolder> </FormFolder>
<FormFolder :default-open="true" class="_formBlock"> <FormFolder :default-open="true" class="_formBlock">
<template #label>{{ i18n.locale.textColor }}</template> <template #label>{{ i18n.ts.textColor }}</template>
<div class="cwepdizn-colors"> <div class="cwepdizn-colors">
<div class="row"> <div class="row">
<button v-for="color in fgColors" :key="color" class="color char _button" :class="{ active: (theme.props.fg === color.forLight) || (theme.props.fg === color.forDark) }" @click="setFgColor(color)"> <button v-for="color in fgColors" :key="color" class="color char _button" :class="{ active: (theme.props.fg === color.forLight) || (theme.props.fg === color.forDark) }" @click="setFgColor(color)">
@ -41,22 +41,22 @@
<FormFolder :default-open="false" class="_formBlock"> <FormFolder :default-open="false" class="_formBlock">
<template #icon><i class="fas fa-code"></i></template> <template #icon><i class="fas fa-code"></i></template>
<template #label>{{ i18n.locale.editCode }}</template> <template #label>{{ i18n.ts.editCode }}</template>
<div class="_formRoot"> <div class="_formRoot">
<FormTextarea v-model="themeCode" tall class="_formBlock"> <FormTextarea v-model="themeCode" tall class="_formBlock">
<template #label>{{ i18n.locale._theme.code }}</template> <template #label>{{ i18n.ts._theme.code }}</template>
</FormTextarea> </FormTextarea>
<FormButton primary class="_formBlock" @click="applyThemeCode">{{ i18n.locale.apply }}</FormButton> <FormButton primary class="_formBlock" @click="applyThemeCode">{{ i18n.ts.apply }}</FormButton>
</div> </div>
</FormFolder> </FormFolder>
<FormFolder :default-open="false" class="_formBlock"> <FormFolder :default-open="false" class="_formBlock">
<template #label>{{ i18n.locale.addDescription }}</template> <template #label>{{ i18n.ts.addDescription }}</template>
<div class="_formRoot"> <div class="_formRoot">
<FormTextarea v-model="description"> <FormTextarea v-model="description">
<template #label>{{ i18n.locale._theme.description }}</template> <template #label>{{ i18n.ts._theme.description }}</template>
</FormTextarea> </FormTextarea>
</div> </div>
</FormFolder> </FormFolder>
@ -167,7 +167,7 @@ function applyThemeCode() {
} catch (err) { } catch (err) {
os.alert({ os.alert({
type: 'error', type: 'error',
text: i18n.locale._theme.invalid, text: i18n.ts._theme.invalid,
}); });
return; return;
} }
@ -177,7 +177,7 @@ function applyThemeCode() {
async function saveAs() { async function saveAs() {
const { canceled, result: name } = await os.inputText({ const { canceled, result: name } = await os.inputText({
title: i18n.locale.name, title: i18n.ts.name,
allowEmpty: false, allowEmpty: false,
}); });
if (canceled) return; if (canceled) return;
@ -204,18 +204,18 @@ watch($$(theme), apply, { deep: true });
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: i18n.locale.themeEditor, title: i18n.ts.themeEditor,
icon: 'fas fa-palette', icon: 'fas fa-palette',
bg: 'var(--bg)', bg: 'var(--bg)',
actions: [{ actions: [{
asFullButton: true, asFullButton: true,
icon: 'fas fa-eye', icon: 'fas fa-eye',
text: i18n.locale.preview, text: i18n.ts.preview,
handler: showPreview, handler: showPreview,
}, { }, {
asFullButton: true, asFullButton: true,
icon: 'fas fa-check', icon: 'fas fa-check',
text: i18n.locale.saveAs, text: i18n.ts.saveAs,
handler: saveAs, handler: saveAs,
}], }],
}, },

View File

@ -64,7 +64,7 @@ async function chooseList(ev: MouseEvent): Promise<void> {
text: list.name, text: list.name,
to: `/timeline/list/${list.id}`, to: `/timeline/list/${list.id}`,
})); }));
os.popupMenu(items, ev.currentTarget || ev.target); os.popupMenu(items, ev.currentTarget ?? ev.target);
} }
async function chooseAntenna(ev: MouseEvent): Promise<void> { async function chooseAntenna(ev: MouseEvent): Promise<void> {
@ -75,7 +75,7 @@ async function chooseAntenna(ev: MouseEvent): Promise<void> {
indicate: antenna.hasUnreadNote, indicate: antenna.hasUnreadNote,
to: `/timeline/antenna/${antenna.id}`, to: `/timeline/antenna/${antenna.id}`,
})); }));
os.popupMenu(items, ev.currentTarget || ev.target); os.popupMenu(items, ev.currentTarget ?? ev.target);
} }
async function chooseChannel(ev: MouseEvent): Promise<void> { async function chooseChannel(ev: MouseEvent): Promise<void> {
@ -86,7 +86,7 @@ async function chooseChannel(ev: MouseEvent): Promise<void> {
indicate: channel.hasUnreadNote, indicate: channel.hasUnreadNote,
to: `/channels/${channel.id}`, to: `/channels/${channel.id}`,
})); }));
os.popupMenu(items, ev.currentTarget || ev.target); os.popupMenu(items, ev.currentTarget ?? ev.target);
} }
function saveSrc(): void { function saveSrc(): void {
@ -97,7 +97,7 @@ function saveSrc(): void {
async function timetravel(): Promise<void> { async function timetravel(): Promise<void> {
const { canceled, result: date } = await os.inputDate({ const { canceled, result: date } = await os.inputDate({
title: i18n.locale.date, title: i18n.ts.date,
}); });
if (canceled) return; if (canceled) return;
@ -110,47 +110,47 @@ function focus(): void {
defineExpose({ defineExpose({
[symbols.PAGE_INFO]: computed(() => ({ [symbols.PAGE_INFO]: computed(() => ({
title: i18n.locale.timeline, title: i18n.ts.timeline,
icon: src === 'local' ? 'fas fa-comments' : src === 'social' ? 'fas fa-share-alt' : src === 'global' ? 'fas fa-globe' : 'fas fa-home', icon: src === 'local' ? 'fas fa-comments' : src === 'social' ? 'fas fa-share-alt' : src === 'global' ? 'fas fa-globe' : 'fas fa-home',
bg: 'var(--bg)', bg: 'var(--bg)',
actions: [{ actions: [{
icon: 'fas fa-list-ul', icon: 'fas fa-list-ul',
text: i18n.locale.lists, text: i18n.ts.lists,
handler: chooseList, handler: chooseList,
}, { }, {
icon: 'fas fa-satellite', icon: 'fas fa-satellite',
text: i18n.locale.antennas, text: i18n.ts.antennas,
handler: chooseAntenna, handler: chooseAntenna,
}, { }, {
icon: 'fas fa-satellite-dish', icon: 'fas fa-satellite-dish',
text: i18n.locale.channel, text: i18n.ts.channel,
handler: chooseChannel, handler: chooseChannel,
}, { }, {
icon: 'fas fa-calendar-alt', icon: 'fas fa-calendar-alt',
text: i18n.locale.jumpToSpecifiedDate, text: i18n.ts.jumpToSpecifiedDate,
handler: timetravel, handler: timetravel,
}], }],
tabs: [{ tabs: [{
active: src === 'home', active: src === 'home',
title: i18n.locale._timelines.home, title: i18n.ts._timelines.home,
icon: 'fas fa-home', icon: 'fas fa-home',
iconOnly: true, iconOnly: true,
onClick: () => { src = 'home'; saveSrc(); }, onClick: () => { src = 'home'; saveSrc(); },
}, ...(isLocalTimelineAvailable ? [{ }, ...(isLocalTimelineAvailable ? [{
active: src === 'local', active: src === 'local',
title: i18n.locale._timelines.local, title: i18n.ts._timelines.local,
icon: 'fas fa-comments', icon: 'fas fa-comments',
iconOnly: true, iconOnly: true,
onClick: () => { src = 'local'; saveSrc(); }, onClick: () => { src = 'local'; saveSrc(); },
}, { }, {
active: src === 'social', active: src === 'social',
title: i18n.locale._timelines.social, title: i18n.ts._timelines.social,
icon: 'fas fa-share-alt', icon: 'fas fa-share-alt',
iconOnly: true, iconOnly: true,
onClick: () => { src = 'social'; saveSrc(); }, onClick: () => { src = 'social'; saveSrc(); },
}] : []), ...(isGlobalTimelineAvailable ? [{ }] : []), ...(isGlobalTimelineAvailable ? [{
active: src === 'global', active: src === 'global',
title: i18n.locale._timelines.global, title: i18n.ts._timelines.global,
icon: 'fas fa-globe', icon: 'fas fa-globe',
iconOnly: true, iconOnly: true,
onClick: () => { src = 'global'; saveSrc(); }, onClick: () => { src = 'global'; saveSrc(); },

View File

@ -264,7 +264,7 @@ export default defineComponent({
}, },
menu(ev) { menu(ev) {
os.popupMenu(getUserMenu(this.user), ev.currentTarget || ev.target); os.popupMenu(getUserMenu(this.user), ev.currentTarget ?? ev.target);
}, },
parallaxLoop() { parallaxLoop() {

View File

@ -135,7 +135,7 @@ export default defineComponent({
action: () => { action: () => {
window.open(`https://misskey-hub.net/help.md`, '_blank'); window.open(`https://misskey-hub.net/help.md`, '_blank');
} }
}], ev.currentTarget || ev.target); }], ev.currentTarget ?? ev.target);
}, },
number number

View File

@ -119,7 +119,7 @@ export default defineComponent({
action: () => { action: () => {
window.open(`https://misskey-hub.net/help.md`, '_blank'); window.open(`https://misskey-hub.net/help.md`, '_blank');
} }
}], ev.currentTarget || ev.target); }], ev.currentTarget ?? ev.target);
}, },
number number

View File

@ -139,7 +139,7 @@ export default defineComponent({
action: () => { action: () => {
window.open(`https://misskey-hub.net/help.md`, '_blank'); window.open(`https://misskey-hub.net/help.md`, '_blank');
} }
}], ev.currentTarget || ev.target); }], ev.currentTarget ?? ev.target);
}, },
number number

View File

@ -27,7 +27,7 @@ export function getNoteMenu(props: {
function del(): void { function del(): void {
os.confirm({ os.confirm({
type: 'warning', type: 'warning',
text: i18n.locale.noteDeleteConfirm, text: i18n.ts.noteDeleteConfirm,
}).then(({ canceled }) => { }).then(({ canceled }) => {
if (canceled) return; if (canceled) return;
@ -40,7 +40,7 @@ export function getNoteMenu(props: {
function delEdit(): void { function delEdit(): void {
os.confirm({ os.confirm({
type: 'warning', type: 'warning',
text: i18n.locale.deleteAndEditConfirm, text: i18n.ts.deleteAndEditConfirm,
}).then(({ canceled }) => { }).then(({ canceled }) => {
if (canceled) return; if (canceled) return;
@ -87,7 +87,7 @@ export function getNoteMenu(props: {
if (e.id === '72dab508-c64d-498f-8740-a8eec1ba385a') { if (e.id === '72dab508-c64d-498f-8740-a8eec1ba385a') {
os.alert({ os.alert({
type: 'error', type: 'error',
text: i18n.locale.pinLimitExceeded text: i18n.ts.pinLimitExceeded
}); });
} }
}); });
@ -97,22 +97,22 @@ export function getNoteMenu(props: {
const clips = await os.api('clips/list'); const clips = await os.api('clips/list');
os.popupMenu([{ os.popupMenu([{
icon: 'fas fa-plus', icon: 'fas fa-plus',
text: i18n.locale.createNew, text: i18n.ts.createNew,
action: async () => { action: async () => {
const { canceled, result } = await os.form(i18n.locale.createNewClip, { const { canceled, result } = await os.form(i18n.ts.createNewClip, {
name: { name: {
type: 'string', type: 'string',
label: i18n.locale.name label: i18n.ts.name
}, },
description: { description: {
type: 'string', type: 'string',
required: false, required: false,
multiline: true, multiline: true,
label: i18n.locale.description label: i18n.ts.description
}, },
isPublic: { isPublic: {
type: 'boolean', type: 'boolean',
label: i18n.locale.public, label: i18n.ts.public,
default: false default: false
} }
}); });
@ -133,7 +133,7 @@ export function getNoteMenu(props: {
async function promote(): Promise<void> { async function promote(): Promise<void> {
const { canceled, result: days } = await os.inputNumber({ const { canceled, result: days } = await os.inputNumber({
title: i18n.locale.numberOfDays, title: i18n.ts.numberOfDays,
}); });
if (canceled) return; if (canceled) return;
@ -171,69 +171,69 @@ export function getNoteMenu(props: {
menu = [{ menu = [{
icon: 'fas fa-copy', icon: 'fas fa-copy',
text: i18n.locale.copyContent, text: i18n.ts.copyContent,
action: copyContent action: copyContent
}, { }, {
icon: 'fas fa-link', icon: 'fas fa-link',
text: i18n.locale.copyLink, text: i18n.ts.copyLink,
action: copyLink action: copyLink
}, (appearNote.url || appearNote.uri) ? { }, (appearNote.url || appearNote.uri) ? {
icon: 'fas fa-external-link-square-alt', icon: 'fas fa-external-link-square-alt',
text: i18n.locale.showOnRemote, text: i18n.ts.showOnRemote,
action: () => { action: () => {
window.open(appearNote.url || appearNote.uri, '_blank'); window.open(appearNote.url || appearNote.uri, '_blank');
} }
} : undefined, } : undefined,
{ {
icon: 'fas fa-share-alt', icon: 'fas fa-share-alt',
text: i18n.locale.share, text: i18n.ts.share,
action: share action: share
}, },
instance.translatorAvailable ? { instance.translatorAvailable ? {
icon: 'fas fa-language', icon: 'fas fa-language',
text: i18n.locale.translate, text: i18n.ts.translate,
action: translate action: translate
} : undefined, } : undefined,
null, null,
statePromise.then(state => state.isFavorited ? { statePromise.then(state => state.isFavorited ? {
icon: 'fas fa-star', icon: 'fas fa-star',
text: i18n.locale.unfavorite, text: i18n.ts.unfavorite,
action: () => toggleFavorite(false) action: () => toggleFavorite(false)
} : { } : {
icon: 'fas fa-star', icon: 'fas fa-star',
text: i18n.locale.favorite, text: i18n.ts.favorite,
action: () => toggleFavorite(true) action: () => toggleFavorite(true)
}), }),
{ {
icon: 'fas fa-paperclip', icon: 'fas fa-paperclip',
text: i18n.locale.clip, text: i18n.ts.clip,
action: () => clip() action: () => clip()
}, },
(appearNote.userId != $i.id) ? statePromise.then(state => state.isWatching ? { (appearNote.userId != $i.id) ? statePromise.then(state => state.isWatching ? {
icon: 'fas fa-eye-slash', icon: 'fas fa-eye-slash',
text: i18n.locale.unwatch, text: i18n.ts.unwatch,
action: () => toggleWatch(false) action: () => toggleWatch(false)
} : { } : {
icon: 'fas fa-eye', icon: 'fas fa-eye',
text: i18n.locale.watch, text: i18n.ts.watch,
action: () => toggleWatch(true) action: () => toggleWatch(true)
}) : undefined, }) : undefined,
statePromise.then(state => state.isMutedThread ? { statePromise.then(state => state.isMutedThread ? {
icon: 'fas fa-comment-slash', icon: 'fas fa-comment-slash',
text: i18n.locale.unmuteThread, text: i18n.ts.unmuteThread,
action: () => toggleThreadMute(false) action: () => toggleThreadMute(false)
} : { } : {
icon: 'fas fa-comment-slash', icon: 'fas fa-comment-slash',
text: i18n.locale.muteThread, text: i18n.ts.muteThread,
action: () => toggleThreadMute(true) action: () => toggleThreadMute(true)
}), }),
appearNote.userId == $i.id ? ($i.pinnedNoteIds || []).includes(appearNote.id) ? { appearNote.userId == $i.id ? ($i.pinnedNoteIds || []).includes(appearNote.id) ? {
icon: 'fas fa-thumbtack', icon: 'fas fa-thumbtack',
text: i18n.locale.unpin, text: i18n.ts.unpin,
action: () => togglePin(false) action: () => togglePin(false)
} : { } : {
icon: 'fas fa-thumbtack', icon: 'fas fa-thumbtack',
text: i18n.locale.pin, text: i18n.ts.pin,
action: () => togglePin(true) action: () => togglePin(true)
} : undefined, } : undefined,
/* /*
@ -241,7 +241,7 @@ export function getNoteMenu(props: {
null, null,
{ {
icon: 'fas fa-bullhorn', icon: 'fas fa-bullhorn',
text: i18n.locale.promote, text: i18n.ts.promote,
action: promote action: promote
}] }]
: [] : []
@ -250,7 +250,7 @@ export function getNoteMenu(props: {
null, null,
{ {
icon: 'fas fa-exclamation-circle', icon: 'fas fa-exclamation-circle',
text: i18n.locale.reportAbuse, text: i18n.ts.reportAbuse,
action: () => { action: () => {
const u = appearNote.url || appearNote.uri || `${url}/notes/${appearNote.id}`; const u = appearNote.url || appearNote.uri || `${url}/notes/${appearNote.id}`;
os.popup(import('@/components/abuse-report-window.vue'), { os.popup(import('@/components/abuse-report-window.vue'), {
@ -265,12 +265,12 @@ export function getNoteMenu(props: {
null, null,
appearNote.userId == $i.id ? { appearNote.userId == $i.id ? {
icon: 'fas fa-edit', icon: 'fas fa-edit',
text: i18n.locale.deleteAndEdit, text: i18n.ts.deleteAndEdit,
action: delEdit action: delEdit
} : undefined, } : undefined,
{ {
icon: 'fas fa-trash-alt', icon: 'fas fa-trash-alt',
text: i18n.locale.delete, text: i18n.ts.delete,
danger: true, danger: true,
action: del action: del
}] }]
@ -280,15 +280,15 @@ export function getNoteMenu(props: {
} else { } else {
menu = [{ menu = [{
icon: 'fas fa-copy', icon: 'fas fa-copy',
text: i18n.locale.copyContent, text: i18n.ts.copyContent,
action: copyContent action: copyContent
}, { }, {
icon: 'fas fa-link', icon: 'fas fa-link',
text: i18n.locale.copyLink, text: i18n.ts.copyLink,
action: copyLink action: copyLink
}, (appearNote.url || appearNote.uri) ? { }, (appearNote.url || appearNote.uri) ? {
icon: 'fas fa-external-link-square-alt', icon: 'fas fa-external-link-square-alt',
text: i18n.locale.showOnRemote, text: i18n.ts.showOnRemote,
action: () => { action: () => {
window.open(appearNote.url || appearNote.uri, '_blank'); window.open(appearNote.url || appearNote.uri, '_blank');
} }

View File

@ -7,11 +7,11 @@ import { i18n } from '@/i18n';
*/ */
export const getNoteSummary = (note: misskey.entities.Note): string => { export const getNoteSummary = (note: misskey.entities.Note): string => {
if (note.deletedAt) { if (note.deletedAt) {
return `(${i18n.locale.deletedNote})`; return `(${i18n.ts.deletedNote})`;
} }
if (note.isHidden) { if (note.isHidden) {
return `(${i18n.locale.invisibleNote})`; return `(${i18n.ts.invisibleNote})`;
} }
let summary = ''; let summary = '';
@ -30,7 +30,7 @@ export const getNoteSummary = (note: misskey.entities.Note): string => {
// 投票が添付されているとき // 投票が添付されているとき
if (note.poll) { if (note.poll) {
summary += ` (${i18n.locale.poll})`; summary += ` (${i18n.ts.poll})`;
} }
// 返信のとき // 返信のとき

View File

@ -11,12 +11,12 @@ export function getUserMenu(user) {
const meId = $i ? $i.id : null; const meId = $i ? $i.id : null;
async function pushList() { async function pushList() {
const t = i18n.locale.selectList; // なぜか後で参照すると null になるので最初にメモリに確保しておく const t = i18n.ts.selectList; // なぜか後で参照すると null になるので最初にメモリに確保しておく
const lists = await os.api('users/lists/list'); const lists = await os.api('users/lists/list');
if (lists.length === 0) { if (lists.length === 0) {
os.alert({ os.alert({
type: 'error', type: 'error',
text: i18n.locale.youHaveNoLists text: i18n.ts.youHaveNoLists
}); });
return; return;
} }
@ -38,12 +38,12 @@ export function getUserMenu(user) {
if (groups.length === 0) { if (groups.length === 0) {
os.alert({ os.alert({
type: 'error', type: 'error',
text: i18n.locale.youHaveNoGroups text: i18n.ts.youHaveNoGroups
}); });
return; return;
} }
const { canceled, result: groupId } = await os.select({ const { canceled, result: groupId } = await os.select({
title: i18n.locale.group, title: i18n.ts.group,
items: groups.map(group => ({ items: groups.map(group => ({
value: group.id, text: group.name value: group.id, text: group.name
})) }))
@ -64,7 +64,7 @@ export function getUserMenu(user) {
} }
async function toggleBlock() { async function toggleBlock() {
if (!await getConfirmed(user.isBlocking ? i18n.locale.unblockConfirm : i18n.locale.blockConfirm)) return; if (!await getConfirmed(user.isBlocking ? i18n.ts.unblockConfirm : i18n.ts.blockConfirm)) return;
os.apiWithDialog(user.isBlocking ? 'blocking/delete' : 'blocking/create', { os.apiWithDialog(user.isBlocking ? 'blocking/delete' : 'blocking/create', {
userId: user.id userId: user.id
@ -119,70 +119,70 @@ export function getUserMenu(user) {
let menu = [{ let menu = [{
icon: 'fas fa-at', icon: 'fas fa-at',
text: i18n.locale.copyUsername, text: i18n.ts.copyUsername,
action: () => { action: () => {
copyToClipboard(`@${user.username}@${user.host || host}`); copyToClipboard(`@${user.username}@${user.host || host}`);
} }
}, { }, {
icon: 'fas fa-info-circle', icon: 'fas fa-info-circle',
text: i18n.locale.info, text: i18n.ts.info,
action: () => { action: () => {
os.pageWindow(`/user-info/${user.id}`); os.pageWindow(`/user-info/${user.id}`);
} }
}, { }, {
icon: 'fas fa-envelope', icon: 'fas fa-envelope',
text: i18n.locale.sendMessage, text: i18n.ts.sendMessage,
action: () => { action: () => {
os.post({ specified: user }); os.post({ specified: user });
} }
}, meId != user.id ? { }, meId != user.id ? {
type: 'link', type: 'link',
icon: 'fas fa-comments', icon: 'fas fa-comments',
text: i18n.locale.startMessaging, text: i18n.ts.startMessaging,
to: '/my/messaging/' + Acct.toString(user), to: '/my/messaging/' + Acct.toString(user),
} : undefined, null, { } : undefined, null, {
icon: 'fas fa-list-ul', icon: 'fas fa-list-ul',
text: i18n.locale.addToList, text: i18n.ts.addToList,
action: pushList action: pushList
}, meId != user.id ? { }, meId != user.id ? {
icon: 'fas fa-users', icon: 'fas fa-users',
text: i18n.locale.inviteToGroup, text: i18n.ts.inviteToGroup,
action: inviteGroup action: inviteGroup
} : undefined] as any; } : undefined] as any;
if ($i && meId != user.id) { if ($i && meId != user.id) {
menu = menu.concat([null, { menu = menu.concat([null, {
icon: user.isMuted ? 'fas fa-eye' : 'fas fa-eye-slash', icon: user.isMuted ? 'fas fa-eye' : 'fas fa-eye-slash',
text: user.isMuted ? i18n.locale.unmute : i18n.locale.mute, text: user.isMuted ? i18n.ts.unmute : i18n.ts.mute,
action: toggleMute action: toggleMute
}, { }, {
icon: 'fas fa-ban', icon: 'fas fa-ban',
text: user.isBlocking ? i18n.locale.unblock : i18n.locale.block, text: user.isBlocking ? i18n.ts.unblock : i18n.ts.block,
action: toggleBlock action: toggleBlock
}]); }]);
if (user.isFollowed) { if (user.isFollowed) {
menu = menu.concat([{ menu = menu.concat([{
icon: 'fas fa-unlink', icon: 'fas fa-unlink',
text: i18n.locale.breakFollow, text: i18n.ts.breakFollow,
action: invalidateFollow action: invalidateFollow
}]); }]);
} }
menu = menu.concat([null, { menu = menu.concat([null, {
icon: 'fas fa-exclamation-circle', icon: 'fas fa-exclamation-circle',
text: i18n.locale.reportAbuse, text: i18n.ts.reportAbuse,
action: reportAbuse action: reportAbuse
}]); }]);
if (iAmModerator) { if (iAmModerator) {
menu = menu.concat([null, { menu = menu.concat([null, {
icon: 'fas fa-microphone-slash', icon: 'fas fa-microphone-slash',
text: user.isSilenced ? i18n.locale.unsilence : i18n.locale.silence, text: user.isSilenced ? i18n.ts.unsilence : i18n.ts.silence,
action: toggleSilence action: toggleSilence
}, { }, {
icon: 'fas fa-snowflake', icon: 'fas fa-snowflake',
text: user.isSuspended ? i18n.locale.unsuspend : i18n.locale.suspend, text: user.isSuspended ? i18n.ts.unsuspend : i18n.ts.suspend,
action: toggleSuspend action: toggleSuspend
}]); }]);
} }
@ -191,7 +191,7 @@ export function getUserMenu(user) {
if ($i && meId === user.id) { if ($i && meId === user.id) {
menu = menu.concat([null, { menu = menu.concat([null, {
icon: 'fas fa-pencil-alt', icon: 'fas fa-pencil-alt',
text: i18n.locale.editProfile, text: i18n.ts.editProfile,
action: () => { action: () => {
router.push('/settings/profile'); router.push('/settings/profile');
} }

View File

@ -1,8 +1,8 @@
export class I18n<T extends Record<string, any>> { export class I18n<T extends Record<string, any>> {
public locale: T; public ts: T;
constructor(locale: T) { constructor(locale: T) {
this.locale = locale; this.ts = locale;
//#region BIND //#region BIND
this.t = this.t.bind(this); this.t = this.t.bind(this);
@ -11,9 +11,9 @@ export class I18n<T extends Record<string, any>> {
// string にしているのは、ドット区切りでのパス指定を許可するため // string にしているのは、ドット区切りでのパス指定を許可するため
// なるべくこのメソッド使うよりもlocale直接参照の方がvueのキャッシュ効いてパフォーマンスが良いかも // なるべくこのメソッド使うよりもlocale直接参照の方がvueのキャッシュ効いてパフォーマンスが良いかも
public t(key: string, args?: Record<string, any>): string { public t(key: string, args?: Record<string, string>): string {
try { try {
let str = key.split('.').reduce((o, i) => o[i], this.locale) as string; let str = key.split('.').reduce((o, i) => o[i], this.ts) as unknown as string;
if (args) { if (args) {
for (const [k, v] of Object.entries(args)) { for (const [k, v] of Object.entries(args)) {
@ -21,7 +21,7 @@ export class I18n<T extends Record<string, any>> {
} }
} }
return str; return str;
} catch (e) { } catch (err) {
console.warn(`missing localization '${key}'`); console.warn(`missing localization '${key}'`);
return key; return key;
} }

View File

@ -4,7 +4,7 @@ import * as os from '@/os';
export async function lookupUser() { export async function lookupUser() {
const { canceled, result } = await os.inputText({ const { canceled, result } = await os.inputText({
title: i18n.locale.usernameOrUserId, title: i18n.ts.usernameOrUserId,
}); });
if (canceled) return; if (canceled) return;
@ -19,7 +19,7 @@ export async function lookupUser() {
if (_notFound) { if (_notFound) {
os.alert({ os.alert({
type: 'error', type: 'error',
text: i18n.locale.noSuchUser text: i18n.ts.noSuchUser
}); });
} else { } else {
_notFound = true; _notFound = true;

View File

@ -6,7 +6,7 @@ export function pleaseLogin() {
if ($i) return; if ($i) return;
alert({ alert({
title: i18n.locale.signinRequired, title: i18n.ts.signinRequired,
text: null text: null
}); });

View File

@ -4,7 +4,7 @@ import { router } from '@/router';
export async function search() { export async function search() {
const { canceled, result: query } = await os.inputText({ const { canceled, result: query } = await os.inputText({
title: i18n.locale.search, title: i18n.ts.search,
}); });
if (canceled || query == null || query === '') return; if (canceled || query == null || query === '') return;
@ -46,7 +46,7 @@ export async function search() {
uri: q uri: q
}); });
os.promiseDialog(promise, null, null, i18n.locale.fetchingAsApObject); os.promiseDialog(promise, null, null, i18n.ts.fetchingAsApObject);
const res = await promise; const res = await promise;

View File

@ -41,9 +41,9 @@ function select(src: any, label: string | null, multiple: boolean): Promise<Driv
const chooseFileFromUrl = () => { const chooseFileFromUrl = () => {
os.inputText({ os.inputText({
title: i18n.locale.uploadFromUrl, title: i18n.ts.uploadFromUrl,
type: 'url', type: 'url',
placeholder: i18n.locale.uploadFromUrlDescription placeholder: i18n.ts.uploadFromUrlDescription
}).then(({ canceled, result: url }) => { }).then(({ canceled, result: url }) => {
if (canceled) return; if (canceled) return;
@ -64,8 +64,8 @@ function select(src: any, label: string | null, multiple: boolean): Promise<Driv
}); });
os.alert({ os.alert({
title: i18n.locale.uploadFromUrlRequested, title: i18n.ts.uploadFromUrlRequested,
text: i18n.locale.uploadFromUrlMayTakeTime text: i18n.ts.uploadFromUrlMayTakeTime
}); });
}); });
}; };
@ -74,15 +74,15 @@ function select(src: any, label: string | null, multiple: boolean): Promise<Driv
text: label, text: label,
type: 'label' type: 'label'
} : undefined, { } : undefined, {
text: i18n.locale.upload, text: i18n.ts.upload,
icon: 'fas fa-upload', icon: 'fas fa-upload',
action: chooseFileFromPc action: chooseFileFromPc
}, { }, {
text: i18n.locale.fromDrive, text: i18n.ts.fromDrive,
icon: 'fas fa-cloud', icon: 'fas fa-cloud',
action: chooseFileFromDrive action: chooseFileFromDrive
}, { }, {
text: i18n.locale.fromUrl, text: i18n.ts.fromUrl,
icon: 'fas fa-link', icon: 'fas fa-link',
action: chooseFileFromUrl action: chooseFileFromUrl
}], src); }], src);

View File

@ -4,7 +4,7 @@ import { i18n } from '@/i18n';
export function showSuspendedDialog() { export function showSuspendedDialog() {
return os.alert({ return os.alert({
type: 'error', type: 'error',
title: i18n.locale.yourAccountSuspendedTitle, title: i18n.ts.yourAccountSuspendedTitle,
text: i18n.locale.yourAccountSuspendedDescription text: i18n.ts.yourAccountSuspendedDescription
}); });
} }

View File

@ -12,7 +12,7 @@ export function useLeaveGuard(enabled: Ref<boolean>) {
const { canceled } = await os.confirm({ const { canceled } = await os.confirm({
type: 'warning', type: 'warning',
text: i18n.locale.leaveConfirm, text: i18n.ts.leaveConfirm,
}); });
return canceled; return canceled;
@ -23,7 +23,7 @@ export function useLeaveGuard(enabled: Ref<boolean>) {
const { canceled } = await os.confirm({ const { canceled } = await os.confirm({
type: 'warning', type: 'warning',
text: i18n.locale.leaveConfirm, text: i18n.ts.leaveConfirm,
}); });
return !canceled; return !canceled;

View File

@ -104,7 +104,7 @@ export default defineComponent({
]; ];
const { canceled, result: column } = await os.select({ const { canceled, result: column } = await os.select({
title: i18n.locale._deck.addColumn, title: i18n.ts._deck.addColumn,
items: columns.map(column => ({ items: columns.map(column => ({
value: column, text: i18n.t('_deck._columns.' + column) value: column, text: i18n.t('_deck._columns.' + column)
})) }))
@ -121,7 +121,7 @@ export default defineComponent({
const onContextmenu = (ev) => { const onContextmenu = (ev) => {
os.contextMenu([{ os.contextMenu([{
text: i18n.locale._deck.addColumn, text: i18n.ts._deck.addColumn,
icon: null, icon: null,
action: addColumn action: addColumn
}], ev); }], ev);

View File

@ -77,12 +77,12 @@ export const loadDeck = async () => {
deckStore.set('columns', [{ deckStore.set('columns', [{
id: 'a', id: 'a',
type: 'main', type: 'main',
name: i18n.locale._deck._columns.main, name: i18n.ts._deck._columns.main,
width: 350, width: 350,
}, { }, {
id: 'b', id: 'b',
type: 'notifications', type: 'notifications',
name: i18n.locale._deck._columns.notifications, name: i18n.ts._deck._columns.notifications,
width: 330, width: 330,
}]); }]);
deckStore.set('layout', [['a'], ['b']]); deckStore.set('layout', [['a'], ['b']]);

View File

@ -171,13 +171,13 @@ export default defineComponent({
text: path, text: path,
}, { }, {
icon: 'fas fa-columns', icon: 'fas fa-columns',
text: i18n.locale.openInSideView, text: i18n.ts.openInSideView,
action: () => { action: () => {
this.$refs.side.navigate(path); this.$refs.side.navigate(path);
} }
}, { }, {
icon: 'fas fa-window-maximize', icon: 'fas fa-window-maximize',
text: i18n.locale.openInWindow, text: i18n.ts.openInWindow,
action: () => { action: () => {
os.pageWindow(path); os.pageWindow(path);
} }

View File

@ -79,13 +79,13 @@ const tick = () => {
month.value = nm + 1; month.value = nm + 1;
day.value = nd; day.value = nd;
weekDay.value = [ weekDay.value = [
i18n.locale._weekday.sunday, i18n.ts._weekday.sunday,
i18n.locale._weekday.monday, i18n.ts._weekday.monday,
i18n.locale._weekday.tuesday, i18n.ts._weekday.tuesday,
i18n.locale._weekday.wednesday, i18n.ts._weekday.wednesday,
i18n.locale._weekday.thursday, i18n.ts._weekday.thursday,
i18n.locale._weekday.friday, i18n.ts._weekday.friday,
i18n.locale._weekday.saturday i18n.ts._weekday.saturday
][now.getDay()]; ][now.getDay()];
const dayNumer = now.getTime() - new Date(ny, nm, nd).getTime(); const dayNumer = now.getTime() - new Date(ny, nm, nd).getTime();

View File

@ -101,22 +101,22 @@ const choose = async (ev) => {
} }
})); }));
os.popupMenu([{ os.popupMenu([{
text: i18n.locale._timelines.home, text: i18n.ts._timelines.home,
icon: 'fas fa-home', icon: 'fas fa-home',
action: () => { setSrc('home') } action: () => { setSrc('home') }
}, { }, {
text: i18n.locale._timelines.local, text: i18n.ts._timelines.local,
icon: 'fas fa-comments', icon: 'fas fa-comments',
action: () => { setSrc('local') } action: () => { setSrc('local') }
}, { }, {
text: i18n.locale._timelines.social, text: i18n.ts._timelines.social,
icon: 'fas fa-share-alt', icon: 'fas fa-share-alt',
action: () => { setSrc('social') } action: () => { setSrc('social') }
}, { }, {
text: i18n.locale._timelines.global, text: i18n.ts._timelines.global,
icon: 'fas fa-globe', icon: 'fas fa-globe',
action: () => { setSrc('global') } action: () => { setSrc('global') }
}, antennaItems.length > 0 ? null : undefined, ...antennaItems, listItems.length > 0 ? null : undefined, ...listItems], ev.currentTarget || ev.target).then(() => { }, antennaItems.length > 0 ? null : undefined, ...antennaItems, listItems.length > 0 ? null : undefined, ...listItems], ev.currentTarget ?? ev.target).then(() => {
menuOpened.value = false; menuOpened.value = false;
}); });
}; };