diff --git a/components/account/AccountCard.vue b/components/account/AccountCard.vue
new file mode 100644
index 00000000..199d587a
--- /dev/null
+++ b/components/account/AccountCard.vue
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/components/account/AccountHeader.vue b/components/account/AccountHeader.vue
index 49cdf0e0..580c5fb6 100644
--- a/components/account/AccountHeader.vue
+++ b/components/account/AccountHeader.vue
@@ -71,9 +71,15 @@ const createdAt = $computed(() => {
-
{{ account.statusesCount }} Posts
-
{{ account.followingCount }} Following
-
{{ account.followersCount }} Followers
+
+ {{ account.statusesCount }} Posts
+
+
+ {{ account.followingCount }} Following
+
+
+ {{ account.followersCount }} Followers
+
diff --git a/components/account/AccountPaginator.client.vue b/components/account/AccountPaginator.client.vue
new file mode 100644
index 00000000..e82fc1ee
--- /dev/null
+++ b/components/account/AccountPaginator.client.vue
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+ Loading...
+
+
+ End of list
+
+
diff --git a/components/timeline/TimelinePaginator.client.vue b/components/timeline/TimelinePaginator.client.vue
index 4e1512dc..61fdaef4 100644
--- a/components/timeline/TimelinePaginator.client.vue
+++ b/components/timeline/TimelinePaginator.client.vue
@@ -5,42 +5,7 @@ const { paginator } = defineProps<{
paginator: Paginator
}>()
-let isLoading = $ref(false)
-let isDone = $ref(false)
-const statuses = $ref([])
-
-const endAnchor = ref()
-const bound = reactive(useElementBounding(endAnchor))
-const isInScreen = $computed(() => bound.top < window.innerHeight * 2)
-
-async function loadNext() {
- if (isLoading || isDone)
- return
-
- // console.log('REQUEST')
- isLoading = true
- const result = await paginator.next()
- if (result.done)
- isDone = true
- if (result.value?.length)
- statuses.push(...result.value)
- isLoading = false
- await nextTick()
- bound.update()
-}
-
-useIntervalFn(() => {
- bound.update()
-}, 1000)
-
-watch(
- () => isInScreen,
- () => {
- if (isInScreen && !isLoading)
- loadNext()
- },
- { immediate: true },
-)
+const { items: statuses, isLoading, isDone, endAnchor } = usePaginator(paginator)
diff --git a/composables/paginator.ts b/composables/paginator.ts
new file mode 100644
index 00000000..82233b22
--- /dev/null
+++ b/composables/paginator.ts
@@ -0,0 +1,41 @@
+import type { Paginator } from 'masto'
+
+export function usePaginator(paginator: Paginator) {
+ let isLoading = $ref(false)
+ let isDone = $ref(false)
+ const items = $ref([])
+
+ const endAnchor = ref()
+ const bound = reactive(useElementBounding(endAnchor))
+ const isInScreen = $computed(() => bound.top < window.innerHeight * 2)
+
+ async function loadNext() {
+ if (isLoading || isDone)
+ return
+
+ isLoading = true
+ const result = await paginator.next()
+ if (result.done)
+ isDone = true
+ if (result.value?.length)
+ items.push(...result.value)
+ isLoading = false
+ await nextTick()
+ bound.update()
+ }
+
+ useIntervalFn(() => {
+ bound.update()
+ }, 1000)
+
+ watch(
+ () => isInScreen,
+ () => {
+ if (isInScreen && !isLoading)
+ loadNext()
+ },
+ { immediate: true },
+ )
+
+ return { items, isLoading, isDone, endAnchor }
+}
diff --git a/pages/@[user]/followers.vue b/pages/@[user]/followers.vue
new file mode 100644
index 00000000..0310e5b1
--- /dev/null
+++ b/pages/@[user]/followers.vue
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/pages/@[user]/following.vue b/pages/@[user]/following.vue
new file mode 100644
index 00000000..309da352
--- /dev/null
+++ b/pages/@[user]/following.vue
@@ -0,0 +1,18 @@
+
+
+
+
+
+