✨ Invite accounts
This commit is contained in:
parent
311700db04
commit
327941455e
2
.github/workflows/nightly.yml
vendored
2
.github/workflows/nightly.yml
vendored
@ -2,7 +2,7 @@ name: release-nightly
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
build-docker:
|
||||
|
@ -65,9 +65,10 @@ func NewRealm(user models.Account, name, description string, realmType int) (mod
|
||||
func ListRealmMember(realmId uint) ([]models.RealmMember, error) {
|
||||
var members []models.RealmMember
|
||||
|
||||
if err := database.C.Where(&models.RealmMember{
|
||||
RealmID: realmId,
|
||||
}).Find(&members).Error; err != nil {
|
||||
if err := database.C.
|
||||
Where(&models.RealmMember{RealmID: realmId}).
|
||||
Preload("Account").
|
||||
Find(&members).Error; err != nil {
|
||||
return members, err
|
||||
}
|
||||
|
||||
|
@ -1,19 +1,20 @@
|
||||
/* eslint-env node */
|
||||
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||
require("@rushstack/eslint-patch/modern-module-resolution")
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
'extends': [
|
||||
'plugin:vue/vue3-essential',
|
||||
'eslint:recommended',
|
||||
'@vue/eslint-config-typescript',
|
||||
'@vue/eslint-config-prettier/skip-formatting'
|
||||
extends: [
|
||||
"plugin:vue/vue3-essential",
|
||||
"eslint:recommended",
|
||||
"@vue/eslint-config-typescript",
|
||||
"@vue/eslint-config-prettier/skip-formatting"
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest'
|
||||
ecmaVersion: "latest"
|
||||
},
|
||||
rules: {
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/valid-v-for': 'off'
|
||||
"vue/multi-word-component-names": "off",
|
||||
"vue/valid-v-for": "off",
|
||||
"vue/require-v-for-key": "off"
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ TypeScript cannot handle type information for `.vue` imports by default, so we r
|
||||
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
|
||||
|
||||
1. Disable the built-in TypeScript Extension
|
||||
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
|
||||
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
|
||||
1. Run `Extensions: Show Built-in Extensions` from VSCode's command palette
|
||||
2. Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
|
||||
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
|
||||
|
||||
## Customize configuration
|
||||
|
@ -1,9 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" type="image/xml+svg" href="/favicon.png">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/xml+svg" href="/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Solarplaza</title>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -1,12 +1,15 @@
|
||||
html, body, #app, .v-application {
|
||||
overflow: auto !important;
|
||||
font-family: "Roboto Sans", ui-sans-serif, system-ui, sans-serif;
|
||||
html,
|
||||
body,
|
||||
#app,
|
||||
.v-application {
|
||||
overflow: auto !important;
|
||||
font-family: "Roboto Sans", ui-sans-serif, system-ui, sans-serif;
|
||||
}
|
||||
|
||||
.no-scrollbar {
|
||||
scrollbar-width: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
width: 0;
|
||||
width: 0;
|
||||
}
|
||||
|
@ -3,13 +3,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import dompurify from "dompurify";
|
||||
import { parse } from "marked";
|
||||
import dompurify from "dompurify"
|
||||
import { parse } from "marked"
|
||||
|
||||
const props = defineProps<{ item: any }>();
|
||||
const props = defineProps<{ item: any }>()
|
||||
|
||||
function parseContent(src: string): string {
|
||||
return dompurify().sanitize(parse(src) as string);
|
||||
return dompurify().sanitize(parse(src) as string)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useEditor } from "@/stores/editor"
|
||||
import { useUserinfo } from "@/stores/userinfo";
|
||||
import { useUserinfo } from "@/stores/userinfo"
|
||||
import { computed } from "vue"
|
||||
|
||||
const id = useUserinfo()
|
||||
|
@ -5,7 +5,7 @@
|
||||
<div class="mb-3 px-1">
|
||||
<v-card>
|
||||
<template #text>
|
||||
<post-item brief :item="item" @update:item="val => updateItem(idx, val)" />
|
||||
<post-item brief :item="item" @update:item="(val) => updateItem(idx, val)" />
|
||||
</template>
|
||||
</v-card>
|
||||
</div>
|
||||
@ -15,14 +15,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import PostItem from "@/components/posts/PostItem.vue";
|
||||
import PostItem from "@/components/posts/PostItem.vue"
|
||||
|
||||
const props = defineProps<{ posts: any[], loader: (opts: any) => Promise<any> }>();
|
||||
const emits = defineEmits(["update:posts"]);
|
||||
const props = defineProps<{ posts: any[]; loader: (opts: any) => Promise<any> }>()
|
||||
const emits = defineEmits(["update:posts"])
|
||||
|
||||
function updateItem(idx: number, data: any) {
|
||||
const posts = JSON.parse(JSON.stringify(props.posts));
|
||||
posts[idx] = data;
|
||||
emits("update:posts", posts);
|
||||
const posts = JSON.parse(JSON.stringify(props.posts))
|
||||
posts[idx] = data
|
||||
emits("update:posts", posts)
|
||||
}
|
||||
</script>
|
||||
|
@ -25,18 +25,37 @@
|
||||
You are editing a post with alias <b class="font-mono">{{ editor.related.edit_to?.alias }}</b>
|
||||
</v-alert>
|
||||
|
||||
<v-textarea required class="mb-3" variant="outlined" label="Content"
|
||||
hint="The content supports markdown syntax" v-model="data.content" @paste="pasteMedia" />
|
||||
<v-textarea
|
||||
required
|
||||
class="mb-3"
|
||||
variant="outlined"
|
||||
label="Content"
|
||||
hint="The content supports markdown syntax"
|
||||
v-model="data.content"
|
||||
@paste="pasteMedia"
|
||||
/>
|
||||
|
||||
<v-expansion-panels>
|
||||
<v-expansion-panel title="Brief describe">
|
||||
<template #text>
|
||||
<div class="mt-1">
|
||||
<v-text-field required variant="solo-filled" density="comfortable" label="Title" :loading="reverting"
|
||||
v-model="data.title" />
|
||||
<v-text-field
|
||||
required
|
||||
variant="solo-filled"
|
||||
density="comfortable"
|
||||
label="Title"
|
||||
:loading="reverting"
|
||||
v-model="data.title"
|
||||
/>
|
||||
|
||||
<v-textarea required auto-grow variant="solo-filled" density="comfortable" label="Description"
|
||||
v-model="data.description" />
|
||||
<v-textarea
|
||||
required
|
||||
auto-grow
|
||||
variant="solo-filled"
|
||||
density="comfortable"
|
||||
label="Description"
|
||||
v-model="data.description"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</v-expansion-panel>
|
||||
@ -47,7 +66,8 @@
|
||||
<div>
|
||||
<p class="text-xs">Your content will visible for public at</p>
|
||||
<p class="text-lg font-medium">
|
||||
{{ data.published_at ? new Date(data.published_at).toLocaleString() : new Date().toLocaleString()
|
||||
{{
|
||||
data.published_at ? new Date(data.published_at).toLocaleString() : new Date().toLocaleString()
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
@ -103,12 +123,12 @@
|
||||
import { request } from "@/scripts/request"
|
||||
import { useEditor } from "@/stores/editor"
|
||||
import { getAtk } from "@/stores/userinfo"
|
||||
import { useRealms } from "@/stores/realms";
|
||||
import { computed, reactive, ref, watch } from "vue";
|
||||
import { useRealms } from "@/stores/realms"
|
||||
import { computed, reactive, ref, watch } from "vue"
|
||||
import { useRoute, useRouter } from "vue-router"
|
||||
import PlannedPublish from "@/components/publish/parts/PlannedPublish.vue"
|
||||
import Media from "@/components/publish/parts/Media.vue"
|
||||
import PublishArea from "@/components/publish/parts/PublishArea.vue";
|
||||
import PublishArea from "@/components/publish/parts/PublishArea.vue"
|
||||
|
||||
const route = useRoute()
|
||||
const realms = useRealms()
|
||||
@ -118,7 +138,7 @@ const dialogs = reactive({
|
||||
plan: false,
|
||||
categories: false,
|
||||
media: false,
|
||||
area: false,
|
||||
area: false
|
||||
})
|
||||
|
||||
const data = ref<any>({
|
||||
|
@ -6,20 +6,40 @@
|
||||
You are editing a post with alias <b class="font-mono">{{ editor.related.edit_to?.alias }}</b>
|
||||
</v-alert>
|
||||
|
||||
<v-textarea required persistent-counter variant="outlined" label="What's happened?!" counter="1024"
|
||||
v-model="data.content" @paste="pasteMedia" />
|
||||
<v-textarea
|
||||
required
|
||||
persistent-counter
|
||||
variant="outlined"
|
||||
label="What's happened?!"
|
||||
counter="1024"
|
||||
v-model="data.content"
|
||||
@paste="pasteMedia"
|
||||
/>
|
||||
|
||||
<div class="flex mt-[-18px]">
|
||||
<v-tooltip text="Planned publish" location="start">
|
||||
<template #activator="{ props }">
|
||||
<v-btn v-bind="props" type="button" variant="text" icon="mdi-calendar" size="small"
|
||||
@click="dialogs.plan = true" />
|
||||
<v-btn
|
||||
v-bind="props"
|
||||
type="button"
|
||||
variant="text"
|
||||
icon="mdi-calendar"
|
||||
size="small"
|
||||
@click="dialogs.plan = true"
|
||||
/>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
<v-tooltip text="Media" location="start">
|
||||
<template #activator="{ props }">
|
||||
<v-btn v-bind="props" icon class="text-none" type="button" variant="text" size="small"
|
||||
@click="dialogs.media = true">
|
||||
<v-btn
|
||||
v-bind="props"
|
||||
icon
|
||||
class="text-none"
|
||||
type="button"
|
||||
variant="text"
|
||||
size="small"
|
||||
@click="dialogs.media = true"
|
||||
>
|
||||
<v-badge v-if="data.attachments.length > 0" :content="data.attachments.length">
|
||||
<v-icon icon="mdi-camera" />
|
||||
</v-badge>
|
||||
|
@ -20,6 +20,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { request } from "@/scripts/request"
|
||||
import { useEditor } from "@/stores/editor"
|
||||
import { getAtk } from "@/stores/userinfo"
|
||||
import { ref } from "vue"
|
||||
@ -35,7 +36,7 @@ async function deletePost() {
|
||||
const url = `/api/p/${target.model_type}/${target.id}`
|
||||
|
||||
loading.value = true
|
||||
const res = await fetch(url, {
|
||||
const res = await request(url, {
|
||||
method: "DELETE",
|
||||
headers: { Authorization: `Bearer ${getAtk()}` }
|
||||
})
|
||||
|
@ -28,10 +28,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRealms } from "@/stores/realms";
|
||||
import { useRealms } from "@/stores/realms"
|
||||
|
||||
const realms = useRealms();
|
||||
const realms = useRealms()
|
||||
|
||||
const props = defineProps<{ show: boolean; value: string | null }>();
|
||||
const emits = defineEmits(["update:show", "update:value"]);
|
||||
const props = defineProps<{ show: boolean; value: string | null }>()
|
||||
const emits = defineEmits(["update:show", "update:value"])
|
||||
</script>
|
||||
|
@ -13,8 +13,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRealms } from "@/stores/realms";
|
||||
import { useUserinfo } from "@/stores/userinfo";
|
||||
import { useRealms } from "@/stores/realms"
|
||||
import { useUserinfo } from "@/stores/userinfo"
|
||||
import { computed } from "vue"
|
||||
|
||||
const id = useUserinfo()
|
||||
|
@ -20,6 +20,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { request } from "@/scripts/request"
|
||||
import { useRealms } from "@/stores/realms"
|
||||
import { getAtk } from "@/stores/userinfo"
|
||||
import { useRoute, useRouter } from "vue-router"
|
||||
@ -40,7 +41,7 @@ async function deletePost() {
|
||||
const url = `/api/realms/${target.id}`
|
||||
|
||||
loading.value = true
|
||||
const res = await fetch(url, {
|
||||
const res = await request(url, {
|
||||
method: "DELETE",
|
||||
headers: { Authorization: `Bearer ${getAtk()}` }
|
||||
})
|
||||
|
@ -4,8 +4,15 @@
|
||||
<v-card-text>
|
||||
<v-text-field label="Name" variant="outlined" density="comfortable" v-model="data.name" />
|
||||
<v-textarea label="Description" variant="outlined" density="comfortable" v-model="data.description" />
|
||||
<v-select label="Realm type" item-title="label" item-value="value" variant="outlined" density="comfortable"
|
||||
:items="realmTypeOptions" v-model="data.realm_type" />
|
||||
<v-select
|
||||
label="Realm type"
|
||||
item-title="label"
|
||||
item-value="value"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
:items="realmTypeOptions"
|
||||
v-model="data.realm_type"
|
||||
/>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
@ -24,6 +31,7 @@
|
||||
import { ref, watch } from "vue"
|
||||
import { getAtk } from "@/stores/userinfo"
|
||||
import { useRealms } from "@/stores/realms"
|
||||
import { request } from "@/scripts/request"
|
||||
|
||||
const emits = defineEmits(["relist"])
|
||||
|
||||
@ -53,7 +61,7 @@ async function submit(evt: SubmitEvent) {
|
||||
const method = realms.related.edit_to ? "PUT" : "POST"
|
||||
|
||||
loading.value = true
|
||||
const res = await fetch(url, {
|
||||
const res = await request(url, {
|
||||
method: method,
|
||||
headers: { "Content-Type": "application/json", Authorization: `Bearer ${getAtk()}` },
|
||||
body: JSON.stringify(payload)
|
||||
|
126
pkg/views/src/components/realms/RealmMembers.vue
Normal file
126
pkg/views/src/components/realms/RealmMembers.vue
Normal file
@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-list density="comfortable" lines="one">
|
||||
<v-list-item v-for="item in members" :title="item.account.nick">
|
||||
<template #prepend>
|
||||
<v-avatar
|
||||
color="grey-lighten-2"
|
||||
icon="mdi-account-circle"
|
||||
class="rounded-card me-2"
|
||||
size="small"
|
||||
:image="item?.account.avatar"
|
||||
/>
|
||||
</template>
|
||||
<template #subtitle>@{{ item.account.name }}</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
||||
<div v-if="isOwned">
|
||||
<v-divider class="mt-2 mb-3 border-opacity-50 mx-[-1rem]" />
|
||||
|
||||
<div class="px-3">
|
||||
<v-dialog class="max-w-[540px]">
|
||||
<template #activator="{ props }">
|
||||
<v-btn v-bind="props" block prepend-icon="mdi-account-plus" variant="plain"> Invite someone </v-btn>
|
||||
</template>
|
||||
|
||||
<template #default="{ isActive }">
|
||||
<v-card prepend-icon="mdi-account-plus" title="Invite someone">
|
||||
<v-form @submit.prevent="inviteMember">
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
label="Username"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
hint="Require username not the nickname"
|
||||
v-model="data.account_name"
|
||||
/>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<v-btn type="reset" color="grey-darken-3" @click="isActive.value = false">Cancel</v-btn>
|
||||
<v-btn type="submit" :disabled="loading">Invite</v-btn>
|
||||
</v-card-actions>
|
||||
</v-form>
|
||||
</v-card>
|
||||
</template>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- @vue-ignore -->
|
||||
<v-snackbar v-model="error" :timeout="5000">Something went wrong... {{ error }}</v-snackbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from "vue"
|
||||
import { request } from "@/scripts/request"
|
||||
import { getAtk, useUserinfo } from "@/stores/userinfo"
|
||||
import { computed } from "vue"
|
||||
|
||||
const id = useUserinfo()
|
||||
|
||||
const props = defineProps<{ item: any }>()
|
||||
|
||||
const data = ref<any>({
|
||||
account_name: ""
|
||||
})
|
||||
|
||||
const members = ref<any[]>([])
|
||||
|
||||
const isOwned = computed(() => {
|
||||
return id.userinfo.data?.id === props.item?.account_id
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
|
||||
watch(
|
||||
() => props.item,
|
||||
(val) => {
|
||||
if (val?.id) {
|
||||
listMembers(val.id)
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
|
||||
async function listMembers(id: number) {
|
||||
loading.value = true
|
||||
const res = await request(`/api/realms/${id}/members`)
|
||||
if (res.status !== 200) {
|
||||
error.value = await res.text()
|
||||
} else {
|
||||
error.value = null
|
||||
members.value = await res.json()
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
async function inviteMember(evt: SubmitEvent) {
|
||||
const form = evt.target as HTMLFormElement
|
||||
const payload = data.value
|
||||
|
||||
loading.value = true
|
||||
const res = await request(`/api/realms/${props.item?.id}/invite`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", Authorization: `Bearer ${getAtk()}` },
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
if (res.status !== 200) {
|
||||
error.value = await res.text()
|
||||
} else {
|
||||
form.reset()
|
||||
await listMembers(props.item?.id)
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.rounded-card {
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
@ -99,7 +99,7 @@ import { useUserinfo } from "@/stores/userinfo"
|
||||
import { useWellKnown } from "@/stores/wellKnown"
|
||||
import PostTools from "@/components/publish/PostTools.vue"
|
||||
import RealmTools from "@/components/realms/RealmTools.vue"
|
||||
import RealmList from "@/components/realms/RealmList.vue";
|
||||
import RealmList from "@/components/realms/RealmList.vue"
|
||||
|
||||
const id = useUserinfo()
|
||||
const editor = useEditor()
|
||||
|
@ -1,32 +1,32 @@
|
||||
import "virtual:uno.css";
|
||||
import "virtual:uno.css"
|
||||
|
||||
import "./assets/utils.css";
|
||||
import "./assets/utils.css"
|
||||
|
||||
import { createApp } from "vue";
|
||||
import { createPinia } from "pinia";
|
||||
import { createApp } from "vue"
|
||||
import { createPinia } from "pinia"
|
||||
|
||||
import "vuetify/styles";
|
||||
import { createVuetify } from "vuetify";
|
||||
import { md3 } from "vuetify/blueprints";
|
||||
import * as components from "vuetify/components";
|
||||
import * as labsComponents from 'vuetify/labs/components'
|
||||
import * as directives from "vuetify/directives";
|
||||
import "vuetify/styles"
|
||||
import { createVuetify } from "vuetify"
|
||||
import { md3 } from "vuetify/blueprints"
|
||||
import * as components from "vuetify/components"
|
||||
import * as labsComponents from "vuetify/labs/components"
|
||||
import * as directives from "vuetify/directives"
|
||||
|
||||
import "@mdi/font/css/materialdesignicons.min.css";
|
||||
import "@fontsource/roboto/latin.css";
|
||||
import "@unocss/reset/tailwind.css";
|
||||
import "@mdi/font/css/materialdesignicons.min.css"
|
||||
import "@fontsource/roboto/latin.css"
|
||||
import "@unocss/reset/tailwind.css"
|
||||
|
||||
import index from "./index.vue";
|
||||
import router from "./router";
|
||||
import index from "./index.vue"
|
||||
import router from "./router"
|
||||
|
||||
const app = createApp(index);
|
||||
const app = createApp(index)
|
||||
|
||||
app.use(
|
||||
createVuetify({
|
||||
directives,
|
||||
components: {
|
||||
...components,
|
||||
...labsComponents,
|
||||
...labsComponents
|
||||
},
|
||||
blueprint: md3,
|
||||
theme: {
|
||||
@ -46,9 +46,9 @@ app.use(
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
)
|
||||
|
||||
app.use(createPinia());
|
||||
app.use(router);
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
|
||||
app.mount("#app");
|
||||
app.mount("#app")
|
||||
|
@ -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),
|
||||
@ -14,7 +14,6 @@ const router = createRouter({
|
||||
component: () => import("@/views/explore.vue")
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
path: "/p/moments/:alias",
|
||||
name: "posts.details.moments",
|
||||
@ -34,6 +33,6 @@ const router = createRouter({
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
})
|
||||
|
||||
export default router;
|
||||
export default router
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { reactive, ref } from "vue"
|
||||
import { defineStore } from "pinia"
|
||||
import { checkLoggedIn, getAtk } from "@/stores/userinfo"
|
||||
import { request } from "@/scripts/request"
|
||||
|
||||
export const useRealms = defineStore("realms", () => {
|
||||
const done = ref(false)
|
||||
@ -20,7 +21,7 @@ export const useRealms = defineStore("realms", () => {
|
||||
async function list() {
|
||||
if (!checkLoggedIn()) return
|
||||
|
||||
const res = await fetch("/api/realms/me/available", {
|
||||
const res = await request("/api/realms/me/available", {
|
||||
headers: { Authorization: `Bearer ${getAtk()}` }
|
||||
})
|
||||
if (res.status !== 200) {
|
||||
|
@ -31,25 +31,25 @@ export const useUserinfo = defineStore("userinfo", () => {
|
||||
|
||||
async function readProfiles() {
|
||||
if (!checkLoggedIn()) {
|
||||
isReady.value = true;
|
||||
}
|
||||
isReady.value = true
|
||||
}
|
||||
|
||||
const res = await request("/api/users/me", {
|
||||
headers: { "Authorization": `Bearer ${getAtk()}` }
|
||||
});
|
||||
const res = await request("/api/users/me", {
|
||||
headers: { Authorization: `Bearer ${getAtk()}` }
|
||||
})
|
||||
|
||||
if (res.status !== 200) {
|
||||
return;
|
||||
}
|
||||
if (res.status !== 200) {
|
||||
return
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
const data = await res.json()
|
||||
|
||||
userinfo.value = {
|
||||
isReady: true,
|
||||
isLoggedIn: true,
|
||||
displayName: data["nick"],
|
||||
data: data
|
||||
};
|
||||
userinfo.value = {
|
||||
isReady: true,
|
||||
isLoggedIn: true,
|
||||
displayName: data["nick"],
|
||||
data: data
|
||||
}
|
||||
}
|
||||
|
||||
return { userinfo, isReady, readProfiles }
|
||||
|
@ -15,46 +15,49 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import PostList from "@/components/posts/PostList.vue";
|
||||
import { reactive, ref } from "vue";
|
||||
import { request } from "@/scripts/request";
|
||||
import PostList from "@/components/posts/PostList.vue"
|
||||
import { reactive, ref } from "vue"
|
||||
import { request } from "@/scripts/request"
|
||||
|
||||
const error = ref<string | null>(null);
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 });
|
||||
const error = ref<string | null>(null)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
|
||||
const posts = ref<any[]>([]);
|
||||
const posts = ref<any[]>([])
|
||||
|
||||
async function readPosts() {
|
||||
const res = await request(`/api/feed?` + new URLSearchParams({
|
||||
take: pagination.pageSize.toString(),
|
||||
offset: ((pagination.page - 1) * pagination.pageSize).toString()
|
||||
}));
|
||||
const res = await request(
|
||||
`/api/feed?` +
|
||||
new URLSearchParams({
|
||||
take: pagination.pageSize.toString(),
|
||||
offset: ((pagination.page - 1) * pagination.pageSize).toString()
|
||||
})
|
||||
)
|
||||
if (res.status !== 200) {
|
||||
error.value = await res.text();
|
||||
error.value = await res.text()
|
||||
} else {
|
||||
error.value = null;
|
||||
const data = await res.json();
|
||||
pagination.total = data["count"];
|
||||
posts.value.push(...(data["data"] ?? []));
|
||||
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;
|
||||
done("empty")
|
||||
return
|
||||
}
|
||||
|
||||
pagination.page++;
|
||||
await readPosts();
|
||||
pagination.page++
|
||||
await readPosts()
|
||||
|
||||
if (error.value != null) done("error");
|
||||
if (error.value != null) done("error")
|
||||
else {
|
||||
if (pagination.total > 0) done("ok");
|
||||
else done("empty");
|
||||
if (pagination.total > 0) done("ok")
|
||||
else done("empty")
|
||||
}
|
||||
}
|
||||
|
||||
readPosts();
|
||||
readPosts()
|
||||
</script>
|
||||
|
@ -5,7 +5,7 @@
|
||||
</div>
|
||||
|
||||
<div class="aside md: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">
|
||||
<v-card :loading="loading">
|
||||
<template #title>
|
||||
<div class="flex justify-between">
|
||||
<span>Realm Info</span>
|
||||
@ -23,6 +23,10 @@
|
||||
</div>
|
||||
</template>
|
||||
</v-card>
|
||||
|
||||
<v-card class="mt-3 pb-3" title="Realm Members">
|
||||
<realm-members :item="metadata" />
|
||||
</v-card>
|
||||
</div>
|
||||
</v-container>
|
||||
</template>
|
||||
@ -36,6 +40,7 @@ import { parse } from "marked"
|
||||
import dompurify from "dompurify"
|
||||
import PostList from "@/components/posts/PostList.vue"
|
||||
import RealmAction from "@/components/realms/RealmAction.vue"
|
||||
import RealmMembers from "@/components/realms/RealmMembers.vue"
|
||||
|
||||
const route = useRoute()
|
||||
const realms = useRealms()
|
||||
|
@ -1,12 +1,6 @@
|
||||
{
|
||||
"extends": "@tsconfig/node20/tsconfig.json",
|
||||
"include": [
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
"cypress.config.*",
|
||||
"nightwatch.conf.*",
|
||||
"playwright.config.*"
|
||||
],
|
||||
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "nightwatch.conf.*", "playwright.config.*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"noEmit": true,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { defineConfig, presetAttributify, presetTypography, presetUno } from "unocss";
|
||||
import { defineConfig, presetAttributify, presetTypography, presetUno } from "unocss"
|
||||
|
||||
export default defineConfig({
|
||||
presets: [presetAttributify(), presetTypography(), presetUno({ preflight: false })]
|
||||
|
Loading…
Reference in New Issue
Block a user