diff --git a/src/client/pages/user/clips.vue b/src/client/pages/user/clips.vue
new file mode 100644
index 0000000000..2a66b6752d
--- /dev/null
+++ b/src/client/pages/user/clips.vue
@@ -0,0 +1,57 @@
+<template>
+<div>
+	<MkPagination :pagination="pagination" #default="{items}" ref="list">
+		<MkA v-for="item in items" :key="item.id" :to="`/clips/${item.id}`" class="item _panel _vMargin">
+			<b>{{ item.name }}</b>
+			<div v-if="item.description" class="description">{{ item.description }}</div>
+		</MkA>
+	</MkPagination>
+</div>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import MkPagination from '@/components/ui/pagination.vue';
+import { userPage, acct } from '../../filters/user';
+
+export default defineComponent({
+	components: {
+		MkPagination,
+	},
+
+	props: {
+		user: {
+			type: Object,
+			required: true
+		},
+	},
+
+	data() {
+		return {
+			pagination: {
+				endpoint: 'users/clips',
+				limit: 20,
+				params: {
+					userId: this.user.id,
+				}
+			},
+		};
+	},
+
+	watch: {
+		user() {
+			this.$refs.list.reload();
+		}
+	},
+
+	methods: {
+		userPage,
+		
+		acct
+	}
+});
+</script>
+
+<style lang="scss" scoped>
+
+</style>
diff --git a/src/client/pages/user/index.vue b/src/client/pages/user/index.vue
index 0c816a2d22..70f6662604 100644
--- a/src/client/pages/user/index.vue
+++ b/src/client/pages/user/index.vue
@@ -60,12 +60,15 @@
 			<div class="main">
 				<div class="nav _vMargin">
 					<MkA :to="userPage(user)" :class="{ active: page === 'index' }" class="link">
+						<Fa :icon="faCommentAlt" class="icon"/>
 						<span>{{ $t('notes') }}</span>
 					</MkA>
 					<MkA :to="userPage(user, 'clips')" :class="{ active: page === 'clips' }" class="link">
+						<Fa :icon="faPaperclip" class="icon"/>
 						<span>{{ $t('clips') }}</span>
 					</MkA>
 					<MkA :to="userPage(user, 'pages')" :class="{ active: page === 'pages' }" class="link">
+						<Fa :icon="faFileAlt" class="icon"/>
 						<span>{{ $t('pages') }}</span>
 					</MkA>
 					<div class="actions">
@@ -83,6 +86,8 @@
 				</template>
 				<XFollowList v-else-if="page === 'following'" type="following" :user="user" class="_vMargin"/>
 				<XFollowList v-else-if="page === 'followers'" type="followers" :user="user" class="_vMargin"/>
+				<XClips v-else-if="page === 'clips'" :user="user" class="_vMargin"/>
+				<XPages v-else-if="page === 'pages'" :user="user" class="_vMargin"/>
 			</div>
 		</div>
 	</div>
@@ -193,8 +198,8 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent, computed } from 'vue';
-import { faExclamationTriangle, faEllipsisH, faRobot, faLock, faBookmark, faChartBar, faImage, faBirthdayCake, faMapMarker } from '@fortawesome/free-solid-svg-icons';
-import { faCalendarAlt, faBookmark as farBookmark } from '@fortawesome/free-regular-svg-icons';
+import { faExclamationTriangle, faEllipsisH, faRobot, faLock, faBookmark, faChartBar, faImage, faBirthdayCake, faMapMarker, faPaperclip, faFileAlt } from '@fortawesome/free-solid-svg-icons';
+import { faCalendarAlt, faBookmark as farBookmark, faCommentAlt } from '@fortawesome/free-regular-svg-icons';
 import * as age from 's-age';
 import XUserTimeline from './index.timeline.vue';
 import XNote from '@/components/note.vue';
@@ -221,6 +226,8 @@ export default defineComponent({
 		MkFolder,
 		MkTab,
 		XFollowList: defineAsyncComponent(() => import('./follow-list.vue')),
+		XClips: defineAsyncComponent(() => import('./clips.vue')),
+		XPages: defineAsyncComponent(() => import('./pages.vue')),
 		XPhotos: defineAsyncComponent(() => import('./index.photos.vue')),
 		XActivity: defineAsyncComponent(() => import('./index.activity.vue')),
 	},
@@ -251,7 +258,7 @@ export default defineComponent({
 			error: null,
 			parallaxAnimationId: null,
 			narrow: null,
-			faExclamationTriangle, faEllipsisH, faRobot, faLock, faBookmark, farBookmark, faChartBar, faImage, faBirthdayCake, faMapMarker, faCalendarAlt
+			faExclamationTriangle, faEllipsisH, faRobot, faLock, faBookmark, farBookmark, faChartBar, faImage, faBirthdayCake, faMapMarker, faCalendarAlt, faCommentAlt, faPaperclip, faFileAlt,
 		};
 	},
 
@@ -471,7 +478,8 @@ export default defineComponent({
 				display: flex;
 				align-items: center;
 				margin-top: var(--margin);
-				font-size: 120%;
+				//font-size: 120%;
+				font-weight: bold;
 
 				> .link {
 					display: inline-block;
@@ -479,6 +487,10 @@ export default defineComponent({
 					text-align: center;
 					border-bottom: solid 3px transparent;
 
+					&:hover {
+						text-decoration: none;
+					}
+
 					&.active {
 						color: var(--accent);
 						border-bottom-color: var(--accent);
diff --git a/src/client/pages/user/pages.vue b/src/client/pages/user/pages.vue
new file mode 100644
index 0000000000..66658ac57d
--- /dev/null
+++ b/src/client/pages/user/pages.vue
@@ -0,0 +1,56 @@
+<template>
+<div>
+	<MkPagination :pagination="pagination" #default="{items}" ref="list">
+		<MkPagePreview v-for="page in items" :page="page" :key="page.id" class="_vMargin"/>
+	</MkPagination>
+</div>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import MkPagePreview from '@/components/page-preview.vue';
+import MkPagination from '@/components/ui/pagination.vue';
+import { userPage, acct } from '../../filters/user';
+
+export default defineComponent({
+	components: {
+		MkPagination,
+		MkPagePreview,
+	},
+
+	props: {
+		user: {
+			type: Object,
+			required: true
+		},
+	},
+
+	data() {
+		return {
+			pagination: {
+				endpoint: 'users/pages',
+				limit: 20,
+				params: {
+					userId: this.user.id,
+				}
+			},
+		};
+	},
+
+	watch: {
+		user() {
+			this.$refs.list.reload();
+		}
+	},
+
+	methods: {
+		userPage,
+		
+		acct
+	}
+});
+</script>
+
+<style lang="scss" scoped>
+
+</style>
diff --git a/src/models/repositories/clip.ts b/src/models/repositories/clip.ts
index 2830546528..11f743349f 100644
--- a/src/models/repositories/clip.ts
+++ b/src/models/repositories/clip.ts
@@ -24,6 +24,12 @@ export class ClipRepository extends Repository<Clip> {
 			isPublic: clip.isPublic,
 		});
 	}
+
+	public packMany(
+		clips: Clip[],
+	) {
+		return Promise.all(clips.map(x => this.pack(x)));
+	}
 }
 
 export const packedClipSchema = {
diff --git a/src/server/api/endpoints/users/clips.ts b/src/server/api/endpoints/users/clips.ts
new file mode 100644
index 0000000000..72aae7252c
--- /dev/null
+++ b/src/server/api/endpoints/users/clips.ts
@@ -0,0 +1,40 @@
+import $ from 'cafy';
+import { ID } from '../../../../misc/cafy-id';
+import define from '../../define';
+import { Clips } from '../../../../models';
+import { makePaginationQuery } from '../../common/make-pagination-query';
+
+export const meta = {
+	tags: ['users', 'clips'],
+
+	params: {
+		userId: {
+			validator: $.type(ID),
+		},
+
+		limit: {
+			validator: $.optional.num.range(1, 100),
+			default: 10
+		},
+
+		sinceId: {
+			validator: $.optional.type(ID),
+		},
+
+		untilId: {
+			validator: $.optional.type(ID),
+		},
+	}
+};
+
+export default define(meta, async (ps, user) => {
+	const query = makePaginationQuery(Clips.createQueryBuilder('clip'), ps.sinceId, ps.untilId)
+		.andWhere(`clip.userId = :userId`, { userId: ps.userId })
+		.andWhere('clip.isPublic = true');
+
+	const clips = await query
+		.take(ps.limit!)
+		.getMany();
+
+	return await Clips.packMany(clips);
+});
diff --git a/src/server/api/endpoints/users/pages.ts b/src/server/api/endpoints/users/pages.ts
new file mode 100644
index 0000000000..706a2e115b
--- /dev/null
+++ b/src/server/api/endpoints/users/pages.ts
@@ -0,0 +1,40 @@
+import $ from 'cafy';
+import { ID } from '../../../../misc/cafy-id';
+import define from '../../define';
+import { Pages } from '../../../../models';
+import { makePaginationQuery } from '../../common/make-pagination-query';
+
+export const meta = {
+	tags: ['users', 'pages'],
+
+	params: {
+		userId: {
+			validator: $.type(ID),
+		},
+
+		limit: {
+			validator: $.optional.num.range(1, 100),
+			default: 10
+		},
+
+		sinceId: {
+			validator: $.optional.type(ID),
+		},
+
+		untilId: {
+			validator: $.optional.type(ID),
+		},
+	}
+};
+
+export default define(meta, async (ps, user) => {
+	const query = makePaginationQuery(Pages.createQueryBuilder('page'), ps.sinceId, ps.untilId)
+		.andWhere(`page.userId = :userId`, { userId: ps.userId })
+		.andWhere('page.visibility = \'public\'');
+
+	const pages = await query
+		.take(ps.limit!)
+		.getMany();
+
+	return await Pages.packMany(pages);
+});