diff --git a/src/web/app/common/views/components/messaging.vue b/src/web/app/common/views/components/messaging.vue
index c1d541894..9f04f8933 100644
--- a/src/web/app/common/views/components/messaging.vue
+++ b/src/web/app/common/views/components/messaging.vue
@@ -12,7 +12,6 @@
 					@keydown="onSearchResultKeydown(i)"
 					@click="navigate(user)"
 					tabindex="-1"
-					:key="user.id"
 				>
 					<img class="avatar" :src="`${user.avatar_url}?thumbnail&size=32`" alt=""/>
 					<span class="name">{{ user.name }}</span>
@@ -38,7 +37,7 @@
 						<mk-time :time="message.created_at"/>
 					</header>
 					<div class="body">
-						<p class="text"><span class="me" v-if="isMe(message)">%i18n:common.tags.mk-messaging.you%:</span>{{ text }}</p>
+						<p class="text"><span class="me" v-if="isMe(message)">%i18n:common.tags.mk-messaging.you%:</span>{{ message.text }}</p>
 					</div>
 				</div>
 			</a>
diff --git a/src/web/app/desktop/views/components/activity.vue b/src/web/app/desktop/views/components/activity.vue
index 1b2cc9afd..33b53eb70 100644
--- a/src/web/app/desktop/views/components/activity.vue
+++ b/src/web/app/desktop/views/components/activity.vue
@@ -1,12 +1,12 @@
 <template>
-<div class="mk-activity">
+<div class="mk-activity" :data-melt="design == 2">
 	<template v-if="design == 0">
 		<p class="title">%fa:chart-bar%%i18n:desktop.tags.mk-activity-widget.title%</p>
 		<button @click="toggle" title="%i18n:desktop.tags.mk-activity-widget.toggle%">%fa:sort%</button>
 	</template>
 	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 	<template v-else>
-		<x-calender v-show="view == 0" :data="[].concat(activity)"/>
+		<x-calendar v-show="view == 0" :data="[].concat(activity)"/>
 		<x-chart v-show="view == 1" :data="[].concat(activity)"/>
 	</template>
 </div>
diff --git a/src/web/app/desktop/views/components/choose-folder-from-drive-window.vue b/src/web/app/desktop/views/components/choose-folder-from-drive-window.vue
index 0e598937e..8111ffcf0 100644
--- a/src/web/app/desktop/views/components/choose-folder-from-drive-window.vue
+++ b/src/web/app/desktop/views/components/choose-folder-from-drive-window.vue
@@ -1,5 +1,5 @@
 <template>
-<mk-window ref="window" is-modal width='800px' height='500px' @closed="$destroy">
+<mk-window ref="window" is-modal width="800px" height="500px" @closed="$destroy">
 	<span slot="header">
 		<span v-html="title" :class="$style.title"></span>
 	</span>
@@ -10,7 +10,7 @@
 		:multiple="false"
 	/>
 	<div :class="$style.footer">
-		<button :class="$style.cancel" @click="close">キャンセル</button>
+		<button :class="$style.cancel" @click="cancel">キャンセル</button>
 		<button :class="$style.ok" @click="ok">決定</button>
 	</div>
 </mk-window>
diff --git a/src/web/app/desktop/views/components/home.vue b/src/web/app/desktop/views/components/home.vue
index 6996584cb..1191ad895 100644
--- a/src/web/app/desktop/views/components/home.vue
+++ b/src/web/app/desktop/views/components/home.vue
@@ -147,7 +147,8 @@ export default Vue.extend({
 			this.$emit('loaded');
 		},
 		onWidgetContextmenu(widgetId) {
-			(this.$refs[widgetId] as any)[0].func();
+			const w = (this.$refs[widgetId] as any)[0];
+			if (w.func) w.func();
 		},
 		onWidgetSort() {
 			this.saveHome();
diff --git a/src/web/app/desktop/views/components/index.ts b/src/web/app/desktop/views/components/index.ts
index 2b5e863ea..3bcfc2fdd 100644
--- a/src/web/app/desktop/views/components/index.ts
+++ b/src/web/app/desktop/views/components/index.ts
@@ -37,6 +37,16 @@ import wBroadcast from './widgets/broadcast.vue';
 import wTimemachine from './widgets/timemachine.vue';
 import wProfile from './widgets/profile.vue';
 import wServer from './widgets/server.vue';
+import wActivity from './widgets/activity.vue';
+import wRss from './widgets/rss.vue';
+import wTrends from './widgets/trends.vue';
+import wVersion from './widgets/version.vue';
+import wUsers from './widgets/users.vue';
+import wPolls from './widgets/polls.vue';
+import wPostForm from './widgets/post-form.vue';
+import wMessaging from './widgets/messaging.vue';
+import wChannel from './widgets/channel.vue';
+import wAccessLog from './widgets/access-log.vue';
 
 Vue.component('mk-ui', ui);
 Vue.component('mk-ui-notification', uiNotification);
@@ -67,7 +77,7 @@ Vue.component('mk-activity', activity);
 Vue.component('mkw-nav', wNav);
 Vue.component('mkw-calendar', wCalendar);
 Vue.component('mkw-photo-stream', wPhotoStream);
-Vue.component('mkw-slideshoe', wSlideshow);
+Vue.component('mkw-slideshow', wSlideshow);
 Vue.component('mkw-tips', wTips);
 Vue.component('mkw-donation', wDonation);
 Vue.component('mkw-notifications', wNotifications);
@@ -75,3 +85,13 @@ Vue.component('mkw-broadcast', wBroadcast);
 Vue.component('mkw-timemachine', wTimemachine);
 Vue.component('mkw-profile', wProfile);
 Vue.component('mkw-server', wServer);
+Vue.component('mkw-activity', wActivity);
+Vue.component('mkw-rss', wRss);
+Vue.component('mkw-trends', wTrends);
+Vue.component('mkw-version', wVersion);
+Vue.component('mkw-users', wUsers);
+Vue.component('mkw-polls', wPolls);
+Vue.component('mkw-post-form', wPostForm);
+Vue.component('mkw-messaging', wMessaging);
+Vue.component('mkw-channel', wChannel);
+Vue.component('mkw-access-log', wAccessLog);
diff --git a/src/web/app/desktop/views/components/widgets/access-log.vue b/src/web/app/desktop/views/components/widgets/access-log.vue
index d9f85e722..ad0a22829 100644
--- a/src/web/app/desktop/views/components/widgets/access-log.vue
+++ b/src/web/app/desktop/views/components/widgets/access-log.vue
@@ -6,7 +6,7 @@
 	<div ref="log">
 		<p v-for="req in requests">
 			<span class="ip" :style="`color:${ req.fg }; background:${ req.bg }`">{{ req.ip }}</span>
-			<span>{{ req.method }}</span>
+			<b>{{ req.method }}</b>
 			<span>{{ req.path }}</span>
 		</p>
 	</div>
@@ -15,7 +15,7 @@
 
 <script lang="ts">
 import define from '../../../../common/define-widget';
-import seedrandom from 'seedrandom';
+import * as seedrandom from 'seedrandom';
 
 export default define({
 	name: 'broadcast',
@@ -101,4 +101,7 @@ export default define({
 			> .ip
 				margin-right 4px
 
+			> b
+				margin-right 4px
+
 </style>
diff --git a/src/web/app/desktop/views/components/widgets/channel.vue b/src/web/app/desktop/views/components/widgets/channel.vue
index 484dca9f6..1b98be734 100644
--- a/src/web/app/desktop/views/components/widgets/channel.vue
+++ b/src/web/app/desktop/views/components/widgets/channel.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="mkw-channel">
-	<template v-if="!data.compact">
+	<template v-if="!props.compact">
 		<p class="title">%fa:tv%{{ channel ? channel.title : '%i18n:desktop.tags.mk-channel-home-widget.title%' }}</p>
 		<button @click="settings" title="%i18n:desktop.tags.mk-channel-home-widget.settings%">%fa:cog%</button>
 	</template>
diff --git a/src/web/app/desktop/views/components/widgets/messaging.vue b/src/web/app/desktop/views/components/widgets/messaging.vue
index 039a524f5..e510a07dc 100644
--- a/src/web/app/desktop/views/components/widgets/messaging.vue
+++ b/src/web/app/desktop/views/components/widgets/messaging.vue
@@ -7,6 +7,8 @@
 
 <script lang="ts">
 import define from '../../../../common/define-widget';
+import MkMessagingRoomWindow from '../messaging-room-window.vue';
+
 export default define({
 	name: 'messaging',
 	props: () => ({
@@ -15,11 +17,11 @@ export default define({
 }).extend({
 	methods: {
 		navigate(user) {
-			if (this.platform == 'desktop') {
-				this.wapi_openMessagingRoomWindow(user);
-			} else {
-				// TODO: open room page in new tab
-			}
+			document.body.appendChild(new MkMessagingRoomWindow({
+				propsData: {
+					user: user
+				}
+			}).$mount().$el);
 		},
 		func() {
 			if (this.props.design == 1) {
diff --git a/src/web/app/desktop/views/components/widgets/post-form.vue b/src/web/app/desktop/views/components/widgets/post-form.vue
index 94b03f84a..ab87ba721 100644
--- a/src/web/app/desktop/views/components/widgets/post-form.vue
+++ b/src/web/app/desktop/views/components/widgets/post-form.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="mkw-post-form">
-	<template v-if="data.design == 0">
+	<template v-if="props.design == 0">
 		<p class="title">%fa:pencil-alt%%i18n:desktop.tags.mk-post-form-home-widget.title%</p>
 	</template>
 	<textarea :disabled="posting" v-model="text" @keydown="onKeydown" placeholder="%i18n:desktop.tags.mk-post-form-home-widget.placeholder%"></textarea>
diff --git a/src/web/app/desktop/views/components/widgets/slideshow.vue b/src/web/app/desktop/views/components/widgets/slideshow.vue
index 75af3c0f1..c2f4eb70d 100644
--- a/src/web/app/desktop/views/components/widgets/slideshow.vue
+++ b/src/web/app/desktop/views/components/widgets/slideshow.vue
@@ -1,8 +1,8 @@
 <template>
 <div class="mkw-slideshow">
 	<div @click="choose">
-		<p v-if="data.folder === undefined">クリックしてフォルダを指定してください</p>
-		<p v-if="data.folder !== undefined && images.length == 0 && !fetching">このフォルダには画像がありません</p>
+		<p v-if="props.folder === undefined">クリックしてフォルダを指定してください</p>
+		<p v-if="props.folder !== undefined && images.length == 0 && !fetching">このフォルダには画像がありません</p>
 		<div ref="slideA" class="slide a"></div>
 		<div ref="slideB" class="slide b"></div>
 	</div>
diff --git a/src/web/app/desktop/views/components/widgets/trends.vue b/src/web/app/desktop/views/components/widgets/trends.vue
index a764639ce..934351b8a 100644
--- a/src/web/app/desktop/views/components/widgets/trends.vue
+++ b/src/web/app/desktop/views/components/widgets/trends.vue
@@ -1,13 +1,13 @@
 <template>
 <div class="mkw-trends">
-	<template v-if="!data.compact">
+	<template v-if="!props.compact">
 		<p class="title">%fa:fire%%i18n:desktop.tags.mk-trends-home-widget.title%</p>
 		<button @click="fetch" title="%i18n:desktop.tags.mk-trends-home-widget.refresh%">%fa:sync%</button>
 	</template>
 	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 	<div class="post" v-else-if="post != null">
-		<p class="text"><a href="/{ post.user.username }/{ post.id }">{ post.text }</a></p>
-		<p class="author">―<a href="/{ post.user.username }">@{ post.user.username }</a></p>
+		<p class="text"><router-link :to="`/${ post.user.username }/${ post.id }`">{{ post.text }}</router-link></p>
+		<p class="author">―<router-link :to="`/${ post.user.username }`">@{{ post.user.username }}</router-link></p>
 	</div>
 	<p class="empty" v-else>%i18n:desktop.tags.mk-trends-home-widget.nothing%</p>
 </div>