Merge branch 'fix-msg-room' of https://github.com/misskey-dev/misskey into fix-msg-room
This commit is contained in:
		
						commit
						6fc1043e1b
					
				
					 95 changed files with 758 additions and 783 deletions
				
			
		| 
						 | 
					@ -15,6 +15,8 @@
 | 
				
			||||||
- 投稿のNSFW画像を表示したあとにリアクションが更新されると画像が非表示になる問題を修正
 | 
					- 投稿のNSFW画像を表示したあとにリアクションが更新されると画像が非表示になる問題を修正
 | 
				
			||||||
- 「クリップ」ページが開かない問題を修正
 | 
					- 「クリップ」ページが開かない問題を修正
 | 
				
			||||||
- トレンドウィジェットが動作しないのを修正
 | 
					- トレンドウィジェットが動作しないのを修正
 | 
				
			||||||
 | 
					- リアクション設定で絵文字ピッカーが開かないのを修正
 | 
				
			||||||
 | 
					- DMページでメンションが含まれる問題を修正
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 12.102.1 (2022/01/27)
 | 
					## 12.102.1 (2022/01/27)
 | 
				
			||||||
### Bugfixes
 | 
					### Bugfixes
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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'
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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">
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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();
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}]
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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(' / ');
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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()"/>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>>();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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}`);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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) => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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: () => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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: () => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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({
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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'; },
 | 
				
			||||||
		},]
 | 
							},]
 | 
				
			||||||
	})),
 | 
						})),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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: [{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	})),
 | 
						})),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,7 @@
 | 
				
			||||||
	<textarea
 | 
						<textarea
 | 
				
			||||||
		ref="textEl"
 | 
							ref="textEl"
 | 
				
			||||||
		v-model="text"
 | 
							v-model="text"
 | 
				
			||||||
		:placeholder="i18n.locale.inputMessageHere"
 | 
							:placeholder="i18n.ts.inputMessageHere"
 | 
				
			||||||
		@keydown="onKeydown"
 | 
							@keydown="onKeydown"
 | 
				
			||||||
		@compositionupdate="onCompositionUpdate"
 | 
							@compositionupdate="onCompositionUpdate"
 | 
				
			||||||
		@paste="onPaste"
 | 
							@paste="onPaste"
 | 
				
			||||||
| 
						 | 
					@ -16,7 +16,7 @@
 | 
				
			||||||
		<div class="buttons">
 | 
							<div class="buttons">
 | 
				
			||||||
			<button class="_button" @click="chooseFile"><i class="fas fa-photo-video"></i></button>
 | 
								<button class="_button" @click="chooseFile"><i class="fas fa-photo-video"></i></button>
 | 
				
			||||||
			<button class="_button" @click="insertEmoji"><i class="fas fa-laugh-squint"></i></button>
 | 
								<button class="_button" @click="insertEmoji"><i class="fas fa-laugh-squint"></i></button>
 | 
				
			||||||
			<button class="send _button" :disabled="!canSend || sending" :title="i18n.locale.send" @click="send">
 | 
								<button class="send _button" :disabled="!canSend || sending" :title="i18n.ts.send" @click="send">
 | 
				
			||||||
				<template v-if="!sending"><i class="fas fa-paper-plane"></i></template><template v-if="sending"><i class="fas fa-spinner fa-pulse fa-fw"></i></template>
 | 
									<template v-if="!sending"><i class="fas fa-paper-plane"></i></template><template v-if="sending"><i class="fas fa-spinner fa-pulse fa-fw"></i></template>
 | 
				
			||||||
			</button>
 | 
								</button>
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
| 
						 | 
					@ -78,7 +78,7 @@ async function onPaste(e: ClipboardEvent) {
 | 
				
			||||||
		if (items[0].kind == 'file') {
 | 
							if (items[0].kind == 'file') {
 | 
				
			||||||
			os.alert({
 | 
								os.alert({
 | 
				
			||||||
				type: 'error',
 | 
									type: 'error',
 | 
				
			||||||
				text: i18n.locale.onlyOneFileCanBeAttached
 | 
									text: i18n.ts.onlyOneFileCanBeAttached
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -107,7 +107,7 @@ function onDrop(e: DragEvent): void {
 | 
				
			||||||
		e.preventDefault();
 | 
							e.preventDefault();
 | 
				
			||||||
		os.alert({
 | 
							os.alert({
 | 
				
			||||||
			type: 'error',
 | 
								type: 'error',
 | 
				
			||||||
			text: i18n.locale.onlyOneFileCanBeAttached
 | 
								text: i18n.ts.onlyOneFileCanBeAttached
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -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.ts.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(() => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@
 | 
				
			||||||
				<template #empty>
 | 
									<template #empty>
 | 
				
			||||||
					<div class="_fullinfo">
 | 
										<div class="_fullinfo">
 | 
				
			||||||
						<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
 | 
											<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
 | 
				
			||||||
						<div>{{ i18n.locale.noMessagesYet }}</div>
 | 
											<div>{{ i18n.ts.noMessagesYet }}</div>
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
				</template>
 | 
									</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,7 @@
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
		<footer>
 | 
							<footer>
 | 
				
			||||||
			<div v-if="typers.length > 0" class="typers">
 | 
								<div v-if="typers.length > 0" class="typers">
 | 
				
			||||||
				<I18n :src="i18n.locale.typingUsers" text-tag="span" class="users">
 | 
									<I18n :src="i18n.ts.typingUsers" text-tag="span" class="users">
 | 
				
			||||||
					<template #users>
 | 
										<template #users>
 | 
				
			||||||
						<b v-for="user in typers" :key="user.id" class="user">{{ user.username }}</b>
 | 
											<b v-for="user in typers" :key="user.id" class="user">{{ user.username }}</b>
 | 
				
			||||||
					</template>
 | 
										</template>
 | 
				
			||||||
| 
						 | 
					@ -32,7 +32,7 @@
 | 
				
			||||||
			</div>
 | 
								</div>
 | 
				
			||||||
			<transition :name="animation ? 'fade' : ''">
 | 
								<transition :name="animation ? 'fade' : ''">
 | 
				
			||||||
				<div class="new-message" v-show="showIndicator">
 | 
									<div class="new-message" v-show="showIndicator">
 | 
				
			||||||
					<button class="_buttonPrimary" @click="onIndicatorClick"><i class="fas fa-fw fa-arrow-circle-down"></i>{{ i18n.locale.newMessageExists }}</button>
 | 
										<button class="_buttonPrimary" @click="onIndicatorClick"><i class="fas fa-fw fa-arrow-circle-down"></i>{{ i18n.ts.newMessageExists }}</button>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
			</transition>
 | 
								</transition>
 | 
				
			||||||
			<XForm v-if="!fetching" ref="formEl" :user="user" :group="group" class="form"/>
 | 
								<XForm v-if="!fetching" ref="formEl" :user="user" :group="group" class="form"/>
 | 
				
			||||||
| 
						 | 
					@ -165,7 +165,7 @@ function onDrop(e: DragEvent): void {
 | 
				
			||||||
	} else if (e.dataTransfer.files.length > 1) {
 | 
						} else if (e.dataTransfer.files.length > 1) {
 | 
				
			||||||
		os.alert({
 | 
							os.alert({
 | 
				
			||||||
			type: 'error',
 | 
								type: 'error',
 | 
				
			||||||
			text: i18n.locale.onlyOneFileCanBeAttached
 | 
								text: i18n.ts.onlyOneFileCanBeAttached
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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: {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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: {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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'; },
 | 
				
			||||||
		},]
 | 
							},]
 | 
				
			||||||
	})),
 | 
						})),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	})),
 | 
						})),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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();
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
		}],
 | 
							}],
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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(); },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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');
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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})`;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 返信のとき
 | 
						// 返信のとき
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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');
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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']]);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue