✨ Realm page
This commit is contained in:
parent
cbea87f74d
commit
d954cb87e6
@ -1,9 +1,5 @@
|
||||
<template>
|
||||
<div class="post-list">
|
||||
<div v-if="props.loading" class="text-center py-8">
|
||||
<v-progress-circular indeterminate />
|
||||
</div>
|
||||
|
||||
<v-infinite-scroll :items="props.posts" :onLoad="props.loader">
|
||||
<template v-for="(item, idx) in props.posts" :key="item">
|
||||
<div class="mb-3 px-1">
|
||||
@ -21,7 +17,7 @@
|
||||
<script setup lang="ts">
|
||||
import PostItem from "@/components/posts/PostItem.vue";
|
||||
|
||||
const props = defineProps<{ loading: boolean, posts: any[], loader: (opts: any) => Promise<any> }>();
|
||||
const props = defineProps<{ posts: any[], loader: (opts: any) => Promise<any> }>();
|
||||
const emits = defineEmits(["update:posts"]);
|
||||
|
||||
function updateItem(idx: number, data: any) {
|
||||
|
@ -1,7 +1,13 @@
|
||||
<template>
|
||||
<v-list density="comfortable">
|
||||
<v-list-subheader>Realms</v-list-subheader>
|
||||
<v-list-item v-for="item in realms" prepend-icon="mdi-account-multiple" :title="item.name" />
|
||||
<v-list-item
|
||||
v-for="item in realms"
|
||||
exact
|
||||
prepend-icon="mdi-account-multiple"
|
||||
:to="{ name: 'realms.details', params: { id: item.id } }"
|
||||
:title="item.name"
|
||||
/>
|
||||
|
||||
<v-divider v-if="realms.length > 0" class="border-opacity-75 my-2" />
|
||||
|
||||
@ -54,12 +60,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { computed, ref } from "vue";
|
||||
import { getAtk, useUserinfo } from "@/stores/userinfo";
|
||||
import { useEditor } from "@/stores/editor";
|
||||
|
||||
const id = useUserinfo();
|
||||
const editor = useEditor();
|
||||
|
||||
const realms = ref<any[]>([]);
|
||||
const realms = computed(() => editor.availableRealms);
|
||||
const requestData = ref({
|
||||
name: "",
|
||||
description: "",
|
||||
@ -80,13 +88,10 @@ const loading = ref(false);
|
||||
|
||||
async function list() {
|
||||
reverting.value = true;
|
||||
const res = await fetch("/api/realms/me/available", {
|
||||
headers: { Authorization: `Bearer ${getAtk()}` }
|
||||
});
|
||||
if (res.status !== 200) {
|
||||
error.value = await res.text();
|
||||
} else {
|
||||
realms.value = await res.json();
|
||||
try {
|
||||
await editor.listRealms();
|
||||
} catch (err) {
|
||||
error.value = (err as Error).message;
|
||||
}
|
||||
reverting.value = false;
|
||||
}
|
||||
@ -111,6 +116,4 @@ async function submit(evt: SubmitEvent) {
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
list();
|
||||
</script>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createRouter, createWebHistory } from "vue-router"
|
||||
import MasterLayout from "@/layouts/master.vue"
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
import MasterLayout from "@/layouts/master.vue";
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
@ -24,10 +24,16 @@ const router = createRouter({
|
||||
path: "/p/articles/:alias",
|
||||
name: "posts.details.articles",
|
||||
component: () => import("@/views/posts/articles.vue")
|
||||
},
|
||||
|
||||
{
|
||||
path: "/realms/:realmId",
|
||||
name: "realms.details",
|
||||
component: () => import("@/views/realms/details.vue")
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
});
|
||||
|
||||
export default router
|
||||
export default router;
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { defineStore } from "pinia"
|
||||
import { reactive, ref } from "vue"
|
||||
import { getAtk } from "@/stores/userinfo"
|
||||
import { defineStore } from "pinia";
|
||||
import { reactive, ref } from "vue";
|
||||
import { checkLoggedIn, getAtk } from "@/stores/userinfo";
|
||||
|
||||
export const useEditor = defineStore("editor", () => {
|
||||
const done = ref(false)
|
||||
const done = ref(false);
|
||||
|
||||
const show = reactive({
|
||||
moment: false,
|
||||
article: false,
|
||||
comment: false,
|
||||
delete: false
|
||||
})
|
||||
});
|
||||
|
||||
const related = reactive<{
|
||||
edit_to: any
|
||||
@ -24,7 +24,24 @@ export const useEditor = defineStore("editor", () => {
|
||||
reply_to: null,
|
||||
repost_to: null,
|
||||
delete_to: null
|
||||
})
|
||||
});
|
||||
|
||||
return { show, related, done }
|
||||
})
|
||||
const availableRealms = ref<any[]>([]);
|
||||
|
||||
async function listRealms() {
|
||||
if (!checkLoggedIn()) return;
|
||||
|
||||
const res = await fetch("/api/realms/me/available", {
|
||||
headers: { Authorization: `Bearer ${getAtk()}` }
|
||||
});
|
||||
if (res.status !== 200) {
|
||||
throw new Error(await res.text());
|
||||
} else {
|
||||
availableRealms.value = await res.json();
|
||||
}
|
||||
}
|
||||
|
||||
listRealms().then(() => console.log("[STARTUP HOOK] Fetch available realm successes."));
|
||||
|
||||
return { show, related, availableRealms, listRealms, done };
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<v-container class="flex max-md:flex-col gap-3 overflow-auto max-h-[calc(100vh-64px)] no-scrollbar">
|
||||
<div class="timeline flex-grow-1 mt-[-16px]">
|
||||
<post-list v-model:posts="posts" :loading="loading" :loader="readMore" />
|
||||
<post-list v-model:posts="posts" :loader="readMore" />
|
||||
</div>
|
||||
|
||||
<div class="aside sticky top-0 w-full h-fit md:min-w-[280px] md:max-w-[320px] max-md:order-first">
|
||||
@ -19,14 +19,12 @@ import PostList from "@/components/posts/PostList.vue";
|
||||
import { reactive, ref } from "vue";
|
||||
import { request } from "@/scripts/request";
|
||||
|
||||
const loading = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 });
|
||||
|
||||
const posts = ref<any[]>([]);
|
||||
|
||||
async function readPosts() {
|
||||
loading.value = true;
|
||||
const res = await request(`/api/feed?` + new URLSearchParams({
|
||||
take: pagination.pageSize.toString(),
|
||||
offset: ((pagination.page - 1) * pagination.pageSize).toString()
|
||||
@ -37,9 +35,8 @@ async function readPosts() {
|
||||
error.value = null;
|
||||
const data = await res.json();
|
||||
pagination.total = data["count"];
|
||||
posts.value.push(...data["data"]);
|
||||
posts.value.push(...(data["data"] ?? []));
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
async function readMore({ done }: any) {
|
||||
@ -52,7 +49,11 @@ async function readMore({ done }: any) {
|
||||
pagination.page++;
|
||||
await readPosts();
|
||||
|
||||
done("ok");
|
||||
if (error.value != null) done("error");
|
||||
else {
|
||||
if (pagination.total > 0) done("ok");
|
||||
else done("empty");
|
||||
}
|
||||
}
|
||||
|
||||
readPosts();
|
||||
|
83
pkg/views/src/views/realms/details.vue
Normal file
83
pkg/views/src/views/realms/details.vue
Normal file
@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<v-container class="flex max-md:flex-col gap-3 overflow-auto max-h-[calc(100vh-64px)] no-scrollbar">
|
||||
<div class="timeline flex-grow-1 mt-[-16px]">
|
||||
<post-list v-model:posts="posts" :loader="readMore" />
|
||||
</div>
|
||||
|
||||
<div class="aside sticky top-0 w-full h-fit md:min-w-[280px] md:max-w-[320px] max-md:order-first">
|
||||
<v-card title="Realm Info" :loading="loading">
|
||||
<template #text>
|
||||
<h2 class="font-medium">Name</h2>
|
||||
<p>{{ metadata?.name }}</p>
|
||||
|
||||
<h2 class="font-medium mt-2">Description</h2>
|
||||
<p>{{ metadata?.description }}</p>
|
||||
</template>
|
||||
</v-card>
|
||||
</div>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from "vue";
|
||||
import { request } from "@/scripts/request";
|
||||
import { useRoute } from "vue-router";
|
||||
import PostList from "@/components/posts/PostList.vue";
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const loading = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 });
|
||||
|
||||
const metadata = ref<any>(null);
|
||||
const posts = ref<any[]>([]);
|
||||
|
||||
async function readMetadata() {
|
||||
loading.value = true;
|
||||
const res = await request(`/api/realms/${route.params.realmId}`);
|
||||
if (res.status !== 200) {
|
||||
error.value = await res.text();
|
||||
} else {
|
||||
error.value = null;
|
||||
metadata.value = await res.json();
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
async function readPosts() {
|
||||
const res = await request(`/api/feed?` + new URLSearchParams({
|
||||
take: pagination.pageSize.toString(),
|
||||
offset: ((pagination.page - 1) * pagination.pageSize).toString(),
|
||||
realmId: route.params.realmId as string
|
||||
}));
|
||||
if (res.status !== 200) {
|
||||
error.value = await res.text();
|
||||
} else {
|
||||
error.value = null;
|
||||
const data = await res.json();
|
||||
pagination.total = data["count"];
|
||||
posts.value.push(...(data["data"] ?? []));
|
||||
}
|
||||
}
|
||||
|
||||
async function readMore({ done }: any) {
|
||||
// Reach the end of data
|
||||
if (pagination.total <= pagination.page * pagination.pageSize) {
|
||||
done("empty");
|
||||
return;
|
||||
}
|
||||
|
||||
pagination.page++;
|
||||
await readPosts();
|
||||
|
||||
if (error.value != null) done("error");
|
||||
else {
|
||||
if (pagination.total > 0) done("ok");
|
||||
else done("empty");
|
||||
}
|
||||
}
|
||||
|
||||
readMetadata();
|
||||
readPosts();
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user