Compare commits
2 Commits
cbea87f74d
...
ea460c3623
Author | SHA1 | Date | |
---|---|---|---|
ea460c3623 | |||
d954cb87e6 |
@ -1,9 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="post-list">
|
<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">
|
<v-infinite-scroll :items="props.posts" :onLoad="props.loader">
|
||||||
<template v-for="(item, idx) in props.posts" :key="item">
|
<template v-for="(item, idx) in props.posts" :key="item">
|
||||||
<div class="mb-3 px-1">
|
<div class="mb-3 px-1">
|
||||||
@ -21,7 +17,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import PostItem from "@/components/posts/PostItem.vue";
|
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"]);
|
const emits = defineEmits(["update:posts"]);
|
||||||
|
|
||||||
function updateItem(idx: number, data: any) {
|
function updateItem(idx: number, data: any) {
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<p class="text-xs">Your content will visible for public at</p>
|
<p class="text-xs">Your content will visible for public at</p>
|
||||||
<p class="text-lg font-medium">
|
<p class="text-lg font-medium">
|
||||||
{{ data.publishedAt ? new Date(data.publishedAt).toLocaleString() : new Date().toLocaleString() }}
|
{{ data.published_at ? new Date(data.published_at).toLocaleString() : new Date().toLocaleString() }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<v-btn size="small" icon="mdi-pencil" variant="text" @click="dialogs.plan = true" />
|
<v-btn size="small" icon="mdi-pencil" variant="text" @click="dialogs.plan = true" />
|
||||||
@ -85,14 +85,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</v-expansion-panel>
|
</v-expansion-panel>
|
||||||
|
|
||||||
|
<v-expansion-panel title="Publish area">
|
||||||
|
<template #text>
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div>
|
||||||
|
<p class="text-xs">This article will publish in</p>
|
||||||
|
<p class="text-lg font-medium">{{ currentRealm?.name ?? "No realm" }}</p>
|
||||||
|
</div>
|
||||||
|
<v-btn size="small" icon="mdi-account-group" variant="text" @click="dialogs.area = true" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</v-expansion-panel>
|
||||||
</v-expansion-panels>
|
</v-expansion-panels>
|
||||||
</v-container>
|
</v-container>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-form>
|
</v-form>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
<planned-publish v-model:show="dialogs.plan" v-model:value="data.publishedAt" />
|
<planned-publish v-model:show="dialogs.plan" v-model:value="data.published_at" />
|
||||||
<media ref="media" v-model:show="dialogs.media" v-model:uploading="uploading" v-model:value="data.attachments" />
|
<media ref="media" v-model:show="dialogs.media" v-model:uploading="uploading" v-model:value="data.attachments" />
|
||||||
|
<publish-area v-model:show="dialogs.area" v-model:value="data.realm_id" />
|
||||||
|
|
||||||
<v-snackbar v-model="success" :timeout="3000">Your article has been published.</v-snackbar>
|
<v-snackbar v-model="success" :timeout="3000">Your article has been published.</v-snackbar>
|
||||||
<v-snackbar v-model="uploading" :timeout="-1">
|
<v-snackbar v-model="uploading" :timeout="-1">
|
||||||
@ -108,27 +121,38 @@
|
|||||||
import { request } from "@/scripts/request"
|
import { request } from "@/scripts/request"
|
||||||
import { useEditor } from "@/stores/editor"
|
import { useEditor } from "@/stores/editor"
|
||||||
import { getAtk } from "@/stores/userinfo"
|
import { getAtk } from "@/stores/userinfo"
|
||||||
import { reactive, ref, watch } from "vue"
|
import { computed, reactive, ref, watch } from "vue";
|
||||||
import { useRouter } from "vue-router"
|
import { useRouter } from "vue-router"
|
||||||
import PlannedPublish from "@/components/publish/parts/PlannedPublish.vue"
|
import PlannedPublish from "@/components/publish/parts/PlannedPublish.vue"
|
||||||
import Media from "@/components/publish/parts/Media.vue"
|
import Media from "@/components/publish/parts/Media.vue"
|
||||||
|
import PublishArea from "@/components/publish/parts/PublishArea.vue";
|
||||||
|
|
||||||
const editor = useEditor()
|
const editor = useEditor()
|
||||||
|
|
||||||
const dialogs = reactive({
|
const dialogs = reactive({
|
||||||
plan: false,
|
plan: false,
|
||||||
categories: false,
|
categories: false,
|
||||||
media: false
|
media: false,
|
||||||
|
area: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
const data = ref<any>({
|
const data = ref<any>({
|
||||||
title: "",
|
title: "",
|
||||||
content: "",
|
content: "",
|
||||||
description: "",
|
description: "",
|
||||||
|
realm_id: null,
|
||||||
published_at: null,
|
published_at: null,
|
||||||
attachments: []
|
attachments: []
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const currentRealm = computed(() => {
|
||||||
|
if(data.value.realm_id) {
|
||||||
|
return editor.availableRealms.find((e) => e.id === data.value.realm_id)
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const error = ref<string | null>(null)
|
const error = ref<string | null>(null)
|
||||||
@ -146,7 +170,8 @@ async function postArticle(evt: SubmitEvent) {
|
|||||||
console.log(payload)
|
console.log(payload)
|
||||||
if (!payload.content) return
|
if (!payload.content) return
|
||||||
if (!payload.title || !payload.description) return
|
if (!payload.title || !payload.description) return
|
||||||
if (!payload.publishedAt) payload.publishedAt = new Date().toISOString()
|
if (!payload.published_at) payload.published_at = new Date().toISOString()
|
||||||
|
if (!payload.realm_id) payload.realm_id = undefined
|
||||||
|
|
||||||
const url = editor.related.edit_to ? `/api/p/articles/${editor.related.edit_to?.id}` : "/api/p/articles"
|
const url = editor.related.edit_to ? `/api/p/articles/${editor.related.edit_to?.id}` : "/api/p/articles"
|
||||||
const method = editor.related.edit_to ? "PUT" : "POST"
|
const method = editor.related.edit_to ? "PUT" : "POST"
|
||||||
|
@ -40,6 +40,18 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</v-tooltip>
|
</v-tooltip>
|
||||||
|
<v-tooltip text="Publish area" location="start">
|
||||||
|
<template #activator="{ props }">
|
||||||
|
<v-btn
|
||||||
|
v-bind="props"
|
||||||
|
type="button"
|
||||||
|
variant="text"
|
||||||
|
icon="mdi-account-group"
|
||||||
|
size="small"
|
||||||
|
@click="dialogs.area = true"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</v-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
@ -54,6 +66,7 @@
|
|||||||
|
|
||||||
<planned-publish v-model:show="dialogs.plan" v-model:value="data.published_at" />
|
<planned-publish v-model:show="dialogs.plan" v-model:value="data.published_at" />
|
||||||
<media v-model:show="dialogs.media" v-model:uploading="uploading" v-model:value="data.attachments" />
|
<media v-model:show="dialogs.media" v-model:uploading="uploading" v-model:value="data.attachments" />
|
||||||
|
<publish-area v-model:show="dialogs.area" v-model:value="data.realm_id" />
|
||||||
|
|
||||||
<v-snackbar v-model="success" :timeout="3000">Your post has been published.</v-snackbar>
|
<v-snackbar v-model="success" :timeout="3000">Your post has been published.</v-snackbar>
|
||||||
<v-snackbar v-model="uploading" :timeout="-1">
|
<v-snackbar v-model="uploading" :timeout="-1">
|
||||||
@ -66,66 +79,70 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { request } from "@/scripts/request"
|
import { request } from "@/scripts/request";
|
||||||
import { useEditor } from "@/stores/editor"
|
import { useEditor } from "@/stores/editor";
|
||||||
import { getAtk } from "@/stores/userinfo"
|
import { getAtk } from "@/stores/userinfo";
|
||||||
import { reactive, ref, watch } from "vue"
|
import { reactive, ref, watch } from "vue";
|
||||||
import { useRouter } from "vue-router"
|
import { useRouter } from "vue-router";
|
||||||
import PlannedPublish from "@/components/publish/parts/PlannedPublish.vue"
|
import PlannedPublish from "@/components/publish/parts/PlannedPublish.vue";
|
||||||
import Media from "@/components/publish/parts/Media.vue"
|
import Media from "@/components/publish/parts/Media.vue";
|
||||||
|
import PublishArea from "@/components/publish/parts/PublishArea.vue";
|
||||||
|
|
||||||
const editor = useEditor()
|
const editor = useEditor();
|
||||||
|
|
||||||
const dialogs = reactive({
|
const dialogs = reactive({
|
||||||
plan: false,
|
plan: false,
|
||||||
media: false
|
media: false,
|
||||||
})
|
area: false
|
||||||
|
});
|
||||||
|
|
||||||
const data = ref<any>({
|
const data = ref<any>({
|
||||||
content: "",
|
content: "",
|
||||||
|
realm_id: null,
|
||||||
published_at: null,
|
published_at: null,
|
||||||
attachments: []
|
attachments: []
|
||||||
})
|
});
|
||||||
|
|
||||||
const error = ref<string | null>(null)
|
const error = ref<string | null>(null);
|
||||||
const success = ref(false)
|
const success = ref(false);
|
||||||
const loading = ref(false)
|
const loading = ref(false);
|
||||||
const uploading = ref(false)
|
const uploading = ref(false);
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter();
|
||||||
|
|
||||||
async function postMoment(evt: SubmitEvent) {
|
async function postMoment(evt: SubmitEvent) {
|
||||||
const form = evt.target as HTMLFormElement
|
const form = evt.target as HTMLFormElement;
|
||||||
const payload = data.value
|
const payload = data.value;
|
||||||
if (!payload.content) return
|
if (!payload.content) return;
|
||||||
if (!payload.published_at) payload.published_at = new Date().toISOString()
|
if (!payload.published_at) payload.published_at = new Date().toISOString();
|
||||||
|
if (!payload.realm_id) payload.realm_id = undefined;
|
||||||
|
|
||||||
const url = editor.related.edit_to ? `/api/p/moments/${editor.related.edit_to?.id}` : "/api/p/moments"
|
const url = editor.related.edit_to ? `/api/p/moments/${editor.related.edit_to?.id}` : "/api/p/moments";
|
||||||
const method = editor.related.edit_to ? "PUT" : "POST"
|
const method = editor.related.edit_to ? "PUT" : "POST";
|
||||||
|
|
||||||
loading.value = true
|
loading.value = true;
|
||||||
const res = await request(url, {
|
const res = await request(url, {
|
||||||
method: method,
|
method: method,
|
||||||
headers: { "Content-Type": "application/json", Authorization: `Bearer ${getAtk()}` },
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${getAtk()}` },
|
||||||
body: JSON.stringify(payload)
|
body: JSON.stringify(payload)
|
||||||
})
|
});
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
form.reset()
|
form.reset();
|
||||||
const data = await res.json()
|
const data = await res.json();
|
||||||
success.value = true
|
success.value = true;
|
||||||
editor.show.moment = false
|
editor.show.moment = false;
|
||||||
router.push({ name: "posts.details.moments", params: { alias: data.alias } })
|
router.push({ name: "posts.details.moments", params: { alias: data.alias } });
|
||||||
} else {
|
} else {
|
||||||
error.value = await res.text()
|
error.value = await res.text();
|
||||||
}
|
}
|
||||||
loading.value = false
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(editor.related, (val) => {
|
watch(editor.related, (val) => {
|
||||||
if (val.edit_to && val.edit_to.model_type === "moment") {
|
if (val.edit_to && val.edit_to.model_type === "moment") {
|
||||||
data.value = val.edit_to
|
data.value = val.edit_to;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
37
pkg/views/src/components/publish/parts/PublishArea.vue
Normal file
37
pkg/views/src/components/publish/parts/PublishArea.vue
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<v-dialog
|
||||||
|
eager
|
||||||
|
class="max-w-[540px]"
|
||||||
|
:model-value="props.show"
|
||||||
|
@update:model-value="(val) => emits('update:show', val)"
|
||||||
|
>
|
||||||
|
<v-card title="Change your audiences">
|
||||||
|
<template #text>
|
||||||
|
<v-select
|
||||||
|
clearable
|
||||||
|
class="mt-2"
|
||||||
|
label="Realm"
|
||||||
|
hint="This field will only show realms you joined. Leave blank to publish this post in public area."
|
||||||
|
variant="solo-filled"
|
||||||
|
item-title="name"
|
||||||
|
item-value="id"
|
||||||
|
:items="editor.availableRealms"
|
||||||
|
:model-value="props.value"
|
||||||
|
@update:model-value="(val) => emits('update:value', val)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #actions>
|
||||||
|
<v-btn class="ms-auto" text="Ok" @click="emits('update:show', false)"></v-btn>
|
||||||
|
</template>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useEditor } from "@/stores/editor";
|
||||||
|
|
||||||
|
const editor = useEditor();
|
||||||
|
|
||||||
|
const props = defineProps<{ show: boolean; value: string | null }>();
|
||||||
|
const emits = defineEmits(["update:show", "update:value"]);
|
||||||
|
</script>
|
@ -1,7 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-list density="comfortable">
|
<v-list density="comfortable">
|
||||||
<v-list-subheader>Realms</v-list-subheader>
|
<v-list-subheader>
|
||||||
<v-list-item v-for="item in realms" prepend-icon="mdi-account-multiple" :title="item.name" />
|
Realms
|
||||||
|
<v-badge
|
||||||
|
color="warning"
|
||||||
|
content="Alpha"
|
||||||
|
inline
|
||||||
|
/>
|
||||||
|
</v-list-subheader>
|
||||||
|
|
||||||
|
<v-list-item
|
||||||
|
v-for="item in realms"
|
||||||
|
exact
|
||||||
|
prepend-icon="mdi-account-multiple"
|
||||||
|
:to="{ name: 'realms.details', params: { realmId: item.id } }"
|
||||||
|
:title="item.name"
|
||||||
|
/>
|
||||||
|
|
||||||
<v-divider v-if="realms.length > 0" class="border-opacity-75 my-2" />
|
<v-divider v-if="realms.length > 0" class="border-opacity-75 my-2" />
|
||||||
|
|
||||||
@ -54,12 +68,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import { getAtk, useUserinfo } from "@/stores/userinfo";
|
import { getAtk, useUserinfo } from "@/stores/userinfo";
|
||||||
|
import { useEditor } from "@/stores/editor";
|
||||||
|
|
||||||
const id = useUserinfo();
|
const id = useUserinfo();
|
||||||
|
const editor = useEditor();
|
||||||
|
|
||||||
const realms = ref<any[]>([]);
|
const realms = computed(() => editor.availableRealms);
|
||||||
const requestData = ref({
|
const requestData = ref({
|
||||||
name: "",
|
name: "",
|
||||||
description: "",
|
description: "",
|
||||||
@ -80,13 +96,10 @@ const loading = ref(false);
|
|||||||
|
|
||||||
async function list() {
|
async function list() {
|
||||||
reverting.value = true;
|
reverting.value = true;
|
||||||
const res = await fetch("/api/realms/me/available", {
|
try {
|
||||||
headers: { Authorization: `Bearer ${getAtk()}` }
|
await editor.listRealms();
|
||||||
});
|
} catch (err) {
|
||||||
if (res.status !== 200) {
|
error.value = (err as Error).message;
|
||||||
error.value = await res.text();
|
|
||||||
} else {
|
|
||||||
realms.value = await res.json();
|
|
||||||
}
|
}
|
||||||
reverting.value = false;
|
reverting.value = false;
|
||||||
}
|
}
|
||||||
@ -111,6 +124,4 @@ async function submit(evt: SubmitEvent) {
|
|||||||
}
|
}
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
list();
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { createRouter, createWebHistory } from "vue-router"
|
import { createRouter, createWebHistory } from "vue-router";
|
||||||
import MasterLayout from "@/layouts/master.vue"
|
import MasterLayout from "@/layouts/master.vue";
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
@ -24,10 +24,16 @@ const router = createRouter({
|
|||||||
path: "/p/articles/:alias",
|
path: "/p/articles/:alias",
|
||||||
name: "posts.details.articles",
|
name: "posts.details.articles",
|
||||||
component: () => import("@/views/posts/articles.vue")
|
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 { defineStore } from "pinia";
|
||||||
import { reactive, ref } from "vue"
|
import { reactive, ref } from "vue";
|
||||||
import { getAtk } from "@/stores/userinfo"
|
import { checkLoggedIn, getAtk } from "@/stores/userinfo";
|
||||||
|
|
||||||
export const useEditor = defineStore("editor", () => {
|
export const useEditor = defineStore("editor", () => {
|
||||||
const done = ref(false)
|
const done = ref(false);
|
||||||
|
|
||||||
const show = reactive({
|
const show = reactive({
|
||||||
moment: false,
|
moment: false,
|
||||||
article: false,
|
article: false,
|
||||||
comment: false,
|
comment: false,
|
||||||
delete: false
|
delete: false
|
||||||
})
|
});
|
||||||
|
|
||||||
const related = reactive<{
|
const related = reactive<{
|
||||||
edit_to: any
|
edit_to: any
|
||||||
@ -24,7 +24,24 @@ export const useEditor = defineStore("editor", () => {
|
|||||||
reply_to: null,
|
reply_to: null,
|
||||||
repost_to: null,
|
repost_to: null,
|
||||||
delete_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>
|
<template>
|
||||||
<v-container class="flex max-md:flex-col gap-3 overflow-auto max-h-[calc(100vh-64px)] no-scrollbar">
|
<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]">
|
<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>
|
||||||
|
|
||||||
<div class="aside sticky top-0 w-full h-fit md:min-w-[280px] md:max-w-[320px] max-md:order-first">
|
<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 { reactive, ref } from "vue";
|
||||||
import { request } from "@/scripts/request";
|
import { request } from "@/scripts/request";
|
||||||
|
|
||||||
const loading = ref(false);
|
|
||||||
const error = ref<string | null>(null);
|
const error = ref<string | null>(null);
|
||||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 });
|
const pagination = reactive({ page: 1, pageSize: 10, total: 0 });
|
||||||
|
|
||||||
const posts = ref<any[]>([]);
|
const posts = ref<any[]>([]);
|
||||||
|
|
||||||
async function readPosts() {
|
async function readPosts() {
|
||||||
loading.value = true;
|
|
||||||
const res = await request(`/api/feed?` + new URLSearchParams({
|
const res = await request(`/api/feed?` + new URLSearchParams({
|
||||||
take: pagination.pageSize.toString(),
|
take: pagination.pageSize.toString(),
|
||||||
offset: ((pagination.page - 1) * pagination.pageSize).toString()
|
offset: ((pagination.page - 1) * pagination.pageSize).toString()
|
||||||
@ -37,9 +35,8 @@ async function readPosts() {
|
|||||||
error.value = null;
|
error.value = null;
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
pagination.total = data["count"];
|
pagination.total = data["count"];
|
||||||
posts.value.push(...data["data"]);
|
posts.value.push(...(data["data"] ?? []));
|
||||||
}
|
}
|
||||||
loading.value = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function readMore({ done }: any) {
|
async function readMore({ done }: any) {
|
||||||
@ -52,7 +49,11 @@ async function readMore({ done }: any) {
|
|||||||
pagination.page++;
|
pagination.page++;
|
||||||
await readPosts();
|
await readPosts();
|
||||||
|
|
||||||
done("ok");
|
if (error.value != null) done("error");
|
||||||
|
else {
|
||||||
|
if (pagination.total > 0) done("ok");
|
||||||
|
else done("empty");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readPosts();
|
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…
x
Reference in New Issue
Block a user