新着ノートをサウンドで通知する機能をdeck UIに追加 (#13867)
* feat(deck-ui): implement note notification * chore: remove notify in antenna * docs(changelog): 新着ノートをサウンドで通知する機能をdeck UIに追加 * fix: type error in test * lint: key order * fix: remove notify column * test: remove test for notify * chore: make sound selectable * fix: add license header * fix: add license header again * Unnecessary await Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> * ファイルを選択してください -> ファイルが選択されていません * fix: i18n忘れ * fix: i18n忘れ * pleaseSelectFile > fileNotSelected --------- Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>
This commit is contained in:
		
							
								
								
									
										71
									
								
								packages/frontend/src/components/MkFormDialog.file.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								packages/frontend/src/components/MkFormDialog.file.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| <!-- | ||||
| SPDX-FileCopyrightText: syuilo and misskey-project | ||||
| SPDX-License-Identifier: AGPL-3.0-only | ||||
| --> | ||||
|  | ||||
| <template> | ||||
| <div> | ||||
| 	<MkButton inline rounded primary @click="selectButton($event)">{{ i18n.ts.selectFile }}</MkButton> | ||||
| 	<div :class="['_nowrap', !fileName && $style.fileNotSelected]">{{ friendlyFileName }}</div> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import { computed, ref } from 'vue'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import MkButton from '@/components/MkButton.vue'; | ||||
| import { selectFile } from '@/scripts/select-file.js'; | ||||
| import { misskeyApi } from '@/scripts/misskey-api.js'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	fileId?: string | null; | ||||
| 	validate?: (file: Misskey.entities.DriveFile) => Promise<boolean>; | ||||
| }>(); | ||||
|  | ||||
| const emit = defineEmits<{ | ||||
| 	(ev: 'update', result: Misskey.entities.DriveFile): void; | ||||
| }>(); | ||||
|  | ||||
| const fileUrl = ref(''); | ||||
| const fileName = ref<string>(''); | ||||
|  | ||||
| const friendlyFileName = computed<string>(() => { | ||||
| 	if (fileName.value) { | ||||
| 		return fileName.value; | ||||
| 	} | ||||
| 	if (fileUrl.value) { | ||||
| 		return fileUrl.value; | ||||
| 	} | ||||
|  | ||||
| 	return i18n.ts.fileNotSelected; | ||||
| }); | ||||
|  | ||||
| if (props.fileId) { | ||||
| 	misskeyApi('drive/files/show', { | ||||
| 		fileId: props.fileId, | ||||
| 	}).then((apiRes) => { | ||||
| 		fileName.value = apiRes.name; | ||||
| 		fileUrl.value = apiRes.url; | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| function selectButton(ev: MouseEvent) { | ||||
| 	selectFile(ev.currentTarget ?? ev.target).then(async (file) => { | ||||
| 		if (!file) return; | ||||
| 		if (props.validate && !await props.validate(file)) return; | ||||
|  | ||||
| 		emit('update', file); | ||||
| 		fileName.value = file.name; | ||||
| 		fileUrl.value = file.url; | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| </script> | ||||
|  | ||||
| <style module> | ||||
| .fileNotSelected { | ||||
| 	font-weight: 700; | ||||
| 	color: var(--infoWarnFg); | ||||
| } | ||||
| </style> | ||||
| @@ -21,8 +21,9 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
|  | ||||
| 	<MkSpacer :marginMin="20" :marginMax="32"> | ||||
| 		<div v-if="Object.keys(form).filter(item => !form[item].hidden).length > 0" class="_gaps_m"> | ||||
| 			<template v-for="(v, k) in Object.fromEntries(Object.entries(form).filter(([_, v]) => !('hidden' in v) || 'hidden' in v && !v.hidden))"> | ||||
| 				<MkInput v-if="v.type === 'number'" v-model="values[k]" type="number" :step="v.step || 1"> | ||||
| 			<template v-for="(v, k) in Object.fromEntries(Object.entries(form))"> | ||||
| 				<template v-if="typeof v.hidden == 'function' ? v.hidden(values) : v.hidden"></template> | ||||
| 				<MkInput v-else-if="v.type === 'number'" v-model="values[k]" type="number" :step="v.step || 1"> | ||||
| 					<template #label><span v-text="v.label || k"></span><span v-if="v.required === false"> ({{ i18n.ts.optional }})</span></template> | ||||
| 					<template v-if="v.description" #caption>{{ v.description }}</template> | ||||
| 				</MkInput> | ||||
| @@ -53,6 +54,12 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 				<MkButton v-else-if="v.type === 'button'" @click="v.action($event, values)"> | ||||
| 					<span v-text="v.content || k"></span> | ||||
| 				</MkButton> | ||||
| 				<XFile | ||||
| 					v-else-if="v.type === 'drive-file'" | ||||
| 					:fileId="v.defaultFileId" | ||||
| 					:validate="async f => !v.validate || await v.validate(f)" | ||||
| 					@update="f => values[k] = f" | ||||
| 				/> | ||||
| 			</template> | ||||
| 		</div> | ||||
| 		<div v-else class="_fullinfo"> | ||||
| @@ -72,6 +79,7 @@ import MkSelect from './MkSelect.vue'; | ||||
| import MkRange from './MkRange.vue'; | ||||
| import MkButton from './MkButton.vue'; | ||||
| import MkRadios from './MkRadios.vue'; | ||||
| import XFile from './MkFormDialog.file.vue'; | ||||
| import type { Form } from '@/scripts/form.js'; | ||||
| import MkModalWindow from '@/components/MkModalWindow.vue'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 anatawa12
					anatawa12