From af8a7e7149714580399f2949a79c3773be7d39df Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Mon, 5 Sep 2022 18:24:46 +0900
Subject: [PATCH 1/4] refactor(client): use setup syntax

---
 .../client/src/components/MkUserPreview.vue   | 94 ++++++++-----------
 1 file changed, 37 insertions(+), 57 deletions(-)

diff --git a/packages/client/src/components/MkUserPreview.vue b/packages/client/src/components/MkUserPreview.vue
index 427e46ef1..4de2e8baa 100644
--- a/packages/client/src/components/MkUserPreview.vue
+++ b/packages/client/src/components/MkUserPreview.vue
@@ -1,7 +1,7 @@
 <template>
-<transition :name="$store.state.animation ? 'popup' : ''" appear @after-leave="$emit('closed')">
-	<div v-if="showing" class="fxxzrfni _popup _shadow" :style="{ zIndex, top: top + 'px', left: left + 'px' }" @mouseover="() => { $emit('mouseover'); }" @mouseleave="() => { $emit('mouseleave'); }">
-		<div v-if="fetched" class="info">
+<transition :name="$store.state.animation ? 'popup' : ''" appear @after-leave="emit('closed')">
+	<div v-if="showing" class="fxxzrfni _popup _shadow" :style="{ zIndex, top: top + 'px', left: left + 'px' }" @mouseover="() => { emit('mouseover'); }" @mouseleave="() => { emit('mouseleave'); }">
+		<div v-if="user != null" class="info">
 			<div class="banner" :style="user.bannerUrl ? `background-image: url(${user.bannerUrl})` : ''">
 				<span v-if="$i && $i.id != user.id && user.isFollowed" class="followed">{{ $ts.followsYou }}</span>
 			</div>
@@ -33,71 +33,51 @@
 </transition>
 </template>
 
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { onMounted } from 'vue';
 import * as Acct from 'misskey-js/built/acct';
+import * as misskey from 'misskey-js';
 import MkFollowButton from '@/components/MkFollowButton.vue';
 import { userPage } from '@/filters/user';
 import * as os from '@/os';
 
-export default defineComponent({
-	components: {
-		MkFollowButton,
-	},
+const props = defineProps<{
+	showing: boolean;
+	q: string;
+	source: HTMLElement;
+}>();
 
-	props: {
-		showing: {
-			type: Boolean,
-			required: true,
-		},
-		q: {
-			type: String,
-			required: true,
-		},
-		source: {
-			required: true,
-		},
-	},
+const emit = defineEmits<{
+	(ev: 'closed'): void;
+	(ev: 'mouseover'): void;
+	(ev: 'mouseleave'): void;
+}>();
 
-	emits: ['closed', 'mouseover', 'mouseleave'],
+const zIndex = os.claimZIndex('middle');
+let user = $ref<misskey.entities.UserDetailed | null>(null);
+let top = $ref(0);
+let left = $ref(0);
 
-	data() {
-		return {
-			user: null,
-			fetched: false,
-			top: 0,
-			left: 0,
-			zIndex: os.claimZIndex('middle'),
-		};
-	},
+onMounted(() => {
+	if (typeof props.q === 'object') {
+		user = props.q;
+	} else {
+		const query = props.q.startsWith('@') ?
+			Acct.parse(props.q.substr(1)) :
+			{ userId: props.q };
 
-	mounted() {
-		if (typeof this.q === 'object') {
-			this.user = this.q;
-			this.fetched = true;
-		} else {
-			const query = this.q.startsWith('@') ?
-				Acct.parse(this.q.substr(1)) :
-				{ userId: this.q };
+		os.api('users/show', query).then(res => {
+			if (!props.showing) return;
+			user = res;
+		});
+	}
 
-			os.api('users/show', query).then(user => {
-				if (!this.showing) return;
-				this.user = user;
-				this.fetched = true;
-			});
-		}
+	const rect = props.source.getBoundingClientRect();
+	const x = ((rect.left + (props.source.offsetWidth / 2)) - (300 / 2)) + window.pageXOffset;
+	const y = rect.top + props.source.offsetHeight + window.pageYOffset;
 
-		const rect = this.source.getBoundingClientRect();
-		const x = ((rect.left + (this.source.offsetWidth / 2)) - (300 / 2)) + window.pageXOffset;
-		const y = rect.top + this.source.offsetHeight + window.pageYOffset;
-
-		this.top = y;
-		this.left = x;
-	},
-
-	methods: {
-		userPage,
-	},
+	top = y;
+	left = x;
 });
 </script>
 

From 19ec6c2abb5fd15999e01327ef2867a5f96d754d Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Mon, 5 Sep 2022 18:34:59 +0900
Subject: [PATCH 2/4] refactor(client): use setup syntax

---
 .../src/components/MkTokenGenerateWindow.vue  | 139 +++++++-----------
 1 file changed, 56 insertions(+), 83 deletions(-)

diff --git a/packages/client/src/components/MkTokenGenerateWindow.vue b/packages/client/src/components/MkTokenGenerateWindow.vue
index bf5775d4d..789218a8c 100644
--- a/packages/client/src/components/MkTokenGenerateWindow.vue
+++ b/packages/client/src/components/MkTokenGenerateWindow.vue
@@ -1,11 +1,12 @@
 <template>
-<XModalWindow ref="dialog"
+<XModalWindow
+	ref="dialog"
 	:width="400"
 	:height="450"
 	:with-ok-button="true"
 	:ok-button-disabled="false"
 	:can-close="false"
-	@close="$refs.dialog.close()"
+	@close="dialog.close()"
 	@closed="$emit('closed')"
 	@ok="ok()"
 >
@@ -27,91 +28,63 @@
 </XModalWindow>
 </template>
 
-<script lang="ts">
-import { defineComponent } from 'vue';
-import { permissions } from 'misskey-js';
-import XModalWindow from '@/components/ui/modal-window.vue';
+<script lang="ts" setup>
+import { } from 'vue';
+import { permissions as kinds } from 'misskey-js';
 import MkInput from './form/input.vue';
-import MkTextarea from './form/textarea.vue';
 import MkSwitch from './form/switch.vue';
 import MkButton from './ui/button.vue';
 import MkInfo from './ui/info.vue';
+import XModalWindow from '@/components/ui/modal-window.vue';
 
-export default defineComponent({
-	components: {
-		XModalWindow,
-		MkInput,
-		MkTextarea,
-		MkSwitch,
-		MkButton,
-		MkInfo,
-	},
-
-	props: {
-		title: {
-			type: String,
-			required: false,
-			default: null
-		},
-		information: {
-			type: String,
-			required: false,
-			default: null
-		},
-		initialName: {
-			type: String,
-			required: false,
-			default: null
-		},
-		initialPermissions: {
-			type: Array,
-			required: false,
-			default: null
-		}
-	},
-
-	emits: ['done', 'closed'],
-
-	data() {
-		return {
-			name: this.initialName,
-			permissions: {},
-			kinds: permissions
-		};
-	},
-
-	created() {
-		if (this.initialPermissions) {
-			for (const kind of this.initialPermissions) {
-				this.permissions[kind] = true;
-			}
-		} else {
-			for (const kind of this.kinds) {
-				this.permissions[kind] = false;
-			}
-		}
-	},
-
-	methods: {
-		ok() {
-			this.$emit('done', {
-				name: this.name,
-				permissions: Object.keys(this.permissions).filter(p => this.permissions[p])
-			});
-			this.$refs.dialog.close();
-		},
-
-		disableAll() {
-			for (const p in this.permissions) {
-				this.permissions[p] = false;
-			}
-		},
-
-		enableAll() {
-			for (const p in this.permissions) {
-				this.permissions[p] = true;
-			}
-		}
-	}
+const props = withDefaults(defineProps<{
+	title?: string | null;
+	information?: string | null;
+	initialName?: string | null;
+	initialPermissions?: string[] | null;
+}>(), {
+	title: null,
+	information: null,
+	initialName: null,
+	initialPermissions: null,
 });
+
+const emit = defineEmits<{
+	(ev: 'closed'): void;
+	(ev: 'done', result: { name: string | null, permissions: string[] }): void;
+}>();
+
+const dialog = $ref<InstanceType<typeof XModalWindow>>();
+let name = $ref(props.initialName);
+let permissions = $ref({});
+
+if (props.initialPermissions) {
+	for (const kind of props.initialPermissions) {
+		permissions[kind] = true;
+	}
+} else {
+	for (const kind of kinds) {
+		permissions[kind] = false;
+	}
+}
+
+function ok(): void {
+	emit('done', {
+		name: name,
+		permissions: Object.keys(permissions).filter(p => permissions[p]),
+	});
+	dialog.close();
+}
+
+function disableAll(): void {
+	for (const p in permissions) {
+		permissions[p] = false;
+	}
+}
+
+function enableAll(): void {
+	for (const p in permissions) {
+		permissions[p] = true;
+	}
+}
 </script>

From ea41851b289d74d5a1929ddec78525761a499c22 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Mon, 5 Sep 2022 18:37:41 +0900
Subject: [PATCH 3/4] refactor(client): use setup syntax

---
 .../src/components/MkUrlPreviewPopup.vue      | 55 +++++++------------
 1 file changed, 20 insertions(+), 35 deletions(-)

diff --git a/packages/client/src/components/MkUrlPreviewPopup.vue b/packages/client/src/components/MkUrlPreviewPopup.vue
index 2f0ffaa38..f343c6d8a 100644
--- a/packages/client/src/components/MkUrlPreviewPopup.vue
+++ b/packages/client/src/components/MkUrlPreviewPopup.vue
@@ -1,52 +1,37 @@
 <template>
 <div class="fgmtyycl" :style="{ zIndex, top: top + 'px', left: left + 'px' }">
-	<transition :name="$store.state.animation ? 'zoom' : ''" @after-leave="$emit('closed')">
+	<transition :name="$store.state.animation ? 'zoom' : ''" @after-leave="emit('closed')">
 		<MkUrlPreview v-if="showing" class="_popup _shadow" :url="url"/>
 	</transition>
 </div>
 </template>
 
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { onMounted } from 'vue';
 import MkUrlPreview from '@/components/MkUrlPreview.vue';
 import * as os from '@/os';
 
-export default defineComponent({
-	components: {
-		MkUrlPreview,
-	},
+const props = defineProps<{
+	showing: boolean;
+	url: string;
+	source: HTMLElement;
+}>();
 
-	props: {
-		url: {
-			type: String,
-			required: true,
-		},
-		source: {
-			required: true,
-		},
-		showing: {
-			type: Boolean,
-			required: true,
-		},
-	},
+const emit = defineEmits<{
+	(ev: 'closed'): void;
+}>();
 
-	data() {
-		return {
-			u: null,
-			top: 0,
-			left: 0,
-			zIndex: os.claimZIndex('middle'),
-		};
-	},
+const zIndex = os.claimZIndex('middle');
+let top = $ref(0);
+let left = $ref(0);
 
-	mounted() {
-		const rect = this.source.getBoundingClientRect();
-		const x = Math.max((rect.left + (this.source.offsetWidth / 2)) - (300 / 2), 6) + window.pageXOffset;
-		const y = rect.top + this.source.offsetHeight + window.pageYOffset;
+onMounted(() => {
+	const rect = props.source.getBoundingClientRect();
+	const x = Math.max((rect.left + (props.source.offsetWidth / 2)) - (300 / 2), 6) + window.pageXOffset;
+	const y = rect.top + props.source.offsetHeight + window.pageYOffset;
 
-		this.top = y;
-		this.left = x;
-	},
+	top = y;
+	left = x;
 });
 </script>
 

From fe8998b43c217fdac5bd03be9877ff1b278f713a Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Mon, 5 Sep 2022 18:51:23 +0900
Subject: [PATCH 4/4] refactor(client): use setup syntax

---
 packages/client/src/components/form/slot.vue  |  10 +-
 packages/client/src/components/global/i18n.ts |   4 +-
 .../client/src/pages/user/index.photos.vue    | 101 ++++++++----------
 3 files changed, 54 insertions(+), 61 deletions(-)

diff --git a/packages/client/src/components/form/slot.vue b/packages/client/src/components/form/slot.vue
index d031b2eff..79ce8fe51 100644
--- a/packages/client/src/components/form/slot.vue
+++ b/packages/client/src/components/form/slot.vue
@@ -8,12 +8,12 @@
 </div>
 </template>
 
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
 
-export default defineComponent({
-
-});
+function focus() {
+	// TODO
+}
 </script>
 
 <style lang="scss" scoped>
diff --git a/packages/client/src/components/global/i18n.ts b/packages/client/src/components/global/i18n.ts
index abf0c9685..1fd293ba1 100644
--- a/packages/client/src/components/global/i18n.ts
+++ b/packages/client/src/components/global/i18n.ts
@@ -30,7 +30,7 @@ export default defineComponent({
 			} else {
 				if (nextBracketOpen > 0) parsed.push(str.substr(0, nextBracketOpen));
 				parsed.push({
-					arg: str.substring(nextBracketOpen + 1, nextBracketClose)
+					arg: str.substring(nextBracketOpen + 1, nextBracketClose),
 				});
 			}
 
@@ -38,5 +38,5 @@ export default defineComponent({
 		}
 
 		return h(this.tag, parsed.map(x => typeof x === 'string' ? (this.textTag ? h(this.textTag, x) : x) : this.$slots[x.arg]()));
-	}
+	},
 });
diff --git a/packages/client/src/pages/user/index.photos.vue b/packages/client/src/pages/user/index.photos.vue
index 2a58b49f6..df733849f 100644
--- a/packages/client/src/pages/user/index.photos.vue
+++ b/packages/client/src/pages/user/index.photos.vue
@@ -4,12 +4,13 @@
 	<div class="ujigsodd">
 		<MkLoading v-if="fetching"/>
 		<div v-if="!fetching && images.length > 0" class="stream">
-			<MkA v-for="image in images"
-				:key="image.id"
+			<MkA
+				v-for="image in images"
+				:key="image.note.id + image.file.id"
 				class="img"
 				:to="notePage(image.note)"
 			>
-				<ImgWithBlurhash :hash="image.blurhash" :src="thumbnail(image.file)" :alt="image.name" :title="image.name"/>
+				<ImgWithBlurhash :hash="image.file.blurhash" :src="thumbnail(image.file)" :title="image.file.name"/>
 			</MkA>
 		</div>
 		<p v-if="!fetching && images.length == 0" class="empty">{{ $ts.nothing }}</p>
@@ -17,64 +18,56 @@
 </MkContainer>
 </template>
 
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { onMounted } from 'vue';
+import * as misskey from 'misskey-js';
 import { getStaticImageUrl } from '@/scripts/get-static-image-url';
 import { notePage } from '@/filters/note';
 import * as os from '@/os';
 import MkContainer from '@/components/ui/container.vue';
 import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
+import { defaultStore } from '@/store';
 
-export default defineComponent({
-	components: {
-		MkContainer,
-		ImgWithBlurhash,
-	},
-	props: {
-		user: {
-			type: Object,
-			required: true
-		},
-	},
-	data() {
-		return {
-			fetching: true,
-			images: [],
-		};
-	},
-	mounted() {
-		const image = [
-			'image/jpeg',
-			'image/png',
-			'image/gif',
-			'image/apng',
-			'image/vnd.mozilla.apng',
-		];
-		os.api('users/notes', {
-			userId: this.user.id,
-			fileType: image,
-			excludeNsfw: this.$store.state.nsfw !== 'ignore',
-			limit: 10,
-		}).then(notes => {
-			for (const note of notes) {
-				for (const file of note.files) {
-					this.images.push({
-						note,
-						file
-					});
-				}
+const props = defineProps<{
+	user: misskey.entities.UserDetailed;
+}>();
+
+let fetching = $ref(true);
+let images = $ref<{
+	note: misskey.entities.Note;
+	file: misskey.entities.DriveFile;
+}[]>([]);
+
+function thumbnail(image: misskey.entities.DriveFile): string {
+	return defaultStore.state.disableShowingAnimatedImages
+		? getStaticImageUrl(image.thumbnailUrl)
+		: image.thumbnailUrl;
+}
+
+onMounted(() => {
+	const image = [
+		'image/jpeg',
+		'image/png',
+		'image/gif',
+		'image/apng',
+		'image/vnd.mozilla.apng',
+	];
+	os.api('users/notes', {
+		userId: props.user.id,
+		fileType: image,
+		excludeNsfw: defaultStore.state.nsfw !== 'ignore',
+		limit: 10,
+	}).then(notes => {
+		for (const note of notes) {
+			for (const file of note.files) {
+				images.push({
+					note,
+					file,
+				});
 			}
-			this.fetching = false;
-		});
-	},
-	methods: {
-		thumbnail(image: any): string {
-			return this.$store.state.disableShowingAnimatedImages
-				? getStaticImageUrl(image.thumbnailUrl)
-				: image.thumbnailUrl;
-		},
-		notePage
-	},
+		}
+		fetching = false;
+	});
 });
 </script>