✨ More places will show menu
This commit is contained in:
parent
b1518f030b
commit
2f87f9bc32
8
.idea/.gitignore
vendored
8
.idea/.gitignore
vendored
@ -1,8 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="WEB_MODULE" version="4">
|
|
||||||
<component name="Go" enabled="true" />
|
|
||||||
<component name="NewModuleRootManager">
|
|
||||||
<content url="file://$MODULE_DIR$" />
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
@ -1,53 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<code_scheme name="Project" version="173">
|
|
||||||
<HTMLCodeStyleSettings>
|
|
||||||
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
|
||||||
</HTMLCodeStyleSettings>
|
|
||||||
<JSCodeStyleSettings version="0">
|
|
||||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
|
||||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
|
||||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
|
||||||
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
|
||||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
|
||||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
|
||||||
</JSCodeStyleSettings>
|
|
||||||
<TypeScriptCodeStyleSettings version="0">
|
|
||||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
|
||||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
|
||||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
|
||||||
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
|
||||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
|
||||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
|
||||||
</TypeScriptCodeStyleSettings>
|
|
||||||
<codeStyleSettings language="HTML">
|
|
||||||
<option name="SOFT_MARGINS" value="120" />
|
|
||||||
<indentOptions>
|
|
||||||
<option name="INDENT_SIZE" value="2" />
|
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
|
||||||
<option name="TAB_SIZE" value="2" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="JavaScript">
|
|
||||||
<option name="SOFT_MARGINS" value="120" />
|
|
||||||
<indentOptions>
|
|
||||||
<option name="INDENT_SIZE" value="2" />
|
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
|
||||||
<option name="TAB_SIZE" value="2" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="TypeScript">
|
|
||||||
<option name="SOFT_MARGINS" value="120" />
|
|
||||||
<indentOptions>
|
|
||||||
<option name="INDENT_SIZE" value="2" />
|
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
|
||||||
<option name="TAB_SIZE" value="2" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="Vue">
|
|
||||||
<option name="SOFT_MARGINS" value="120" />
|
|
||||||
<indentOptions>
|
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
</code_scheme>
|
|
||||||
</component>
|
|
@ -1,5 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<state>
|
|
||||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
|
||||||
</state>
|
|
||||||
</component>
|
|
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
|
||||||
<data-source source="LOCAL" name="hy_interactive@localhost" uuid="2e2101b2-4037-47ee-88ed-456dc2cb4423">
|
|
||||||
<driver-ref>postgresql</driver-ref>
|
|
||||||
<synchronize>true</synchronize>
|
|
||||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
|
||||||
<jdbc-url>jdbc:postgresql://localhost:5432/hy_interactive</jdbc-url>
|
|
||||||
<working-dir>$ProjectFileDir$</working-dir>
|
|
||||||
</data-source>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,11 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<profile version="1.0">
|
|
||||||
<option name="myName" value="Project Default" />
|
|
||||||
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
|
||||||
<Languages>
|
|
||||||
<language minSize="54" name="TypeScript" />
|
|
||||||
</Languages>
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="SqlDialectInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/Interactive.iml" filepath="$PROJECT_DIR$/.idea/Interactive.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="SqlDialectMappings">
|
|
||||||
<file url="file://$PROJECT_DIR$/pkg/server/moments_api.go" dialect="PostgreSQL" />
|
|
||||||
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/2e2101b2-4037-47ee-88ed-456dc2cb4423/console.sql" dialect="PostgreSQL" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -11,5 +11,9 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaVersion: 'latest'
|
ecmaVersion: 'latest'
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'vue/multi-word-component-names': 'off',
|
||||||
|
'vue/valid-v-for': 'off'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
43
pkg/views/src/components/posts/PostAction.vue
Normal file
43
pkg/views/src/components/posts/PostAction.vue
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<v-menu>
|
||||||
|
<template #activator="{ props }">
|
||||||
|
<v-btn v-bind="props" icon="mdi-dots-vertical" variant="text" size="x-small" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<v-list density="compact" lines="one">
|
||||||
|
<v-list-item disabled append-icon="mdi-flag" title="Report" />
|
||||||
|
<v-list-item v-if="isOwned" append-icon="mdi-pencil" title="Edit" @click="editPost" />
|
||||||
|
<v-list-item v-if="isOwned" append-icon="mdi-delete" title="Delete" @click="deletePost" />
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useEditor } from "@/stores/editor"
|
||||||
|
import { useUserinfo } from "@/stores/userinfo";
|
||||||
|
import { computed } from "vue"
|
||||||
|
|
||||||
|
const id = useUserinfo()
|
||||||
|
const editor = useEditor()
|
||||||
|
|
||||||
|
const props = defineProps<{ item: any }>()
|
||||||
|
|
||||||
|
const isOwned = computed(() => props.item?.author_id === id.userinfo.data.id)
|
||||||
|
|
||||||
|
function editPost() {
|
||||||
|
editor.related.edit_to = props.item
|
||||||
|
if (editor.show.hasOwnProperty(props.item.model_type)) {
|
||||||
|
// @ts-ignore
|
||||||
|
editor.show[props.item.model_type] = true
|
||||||
|
}
|
||||||
|
if (props.item.model_type === "comment") {
|
||||||
|
editor.related.comment_to = props.item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deletePost() {
|
||||||
|
editor.related.delete_to = JSON.parse(JSON.stringify(props.item))
|
||||||
|
editor.related.delete_to.model_type = props.item.model_type + "s"
|
||||||
|
editor.show.delete = true
|
||||||
|
}
|
||||||
|
</script>
|
@ -9,7 +9,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-grow-1 relative">
|
<div class="flex-grow-1">
|
||||||
<div class="font-bold">{{ props.item?.author.nick }}</div>
|
<div class="font-bold">{{ props.item?.author.nick }}</div>
|
||||||
|
|
||||||
<div v-if="props.item?.model_type === 'article'" class="text-xs text-grey-darken-4 mb-2">
|
<div v-if="props.item?.model_type === 'article'" class="text-xs text-grey-darken-4 mb-2">
|
||||||
@ -36,66 +36,35 @@
|
|||||||
<div class="mt-1 text-xs opacity-80 flex gap-2 items-center">
|
<div class="mt-1 text-xs opacity-80 flex gap-2 items-center">
|
||||||
<span>Posted at {{ new Date(props.item?.created_at).toLocaleString() }}</span>
|
<span>Posted at {{ new Date(props.item?.created_at).toLocaleString() }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-menu>
|
|
||||||
<template #activator="{ props }">
|
|
||||||
<div class="absolute right-0 top-0">
|
|
||||||
<v-btn v-bind="props" icon="mdi-dots-vertical" variant="text" size="x-small" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
|
||||||
|
|
||||||
<v-list density="compact" lines="one">
|
<div>
|
||||||
<v-list-item disabled append-icon="mdi-flag" title="Report" />
|
<post-action :item="props.item" />
|
||||||
<v-list-item v-if="isOwned" append-icon="mdi-pencil" title="Edit" @click="editPost" />
|
|
||||||
<v-list-item v-if="isOwned" append-icon="mdi-delete" title="Delete" @click="deletePost" />
|
|
||||||
</v-list>
|
|
||||||
</v-menu>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, type Component } from "vue"
|
import { type Component } from "vue"
|
||||||
import { useUserinfo } from "@/stores/userinfo"
|
import { useUserinfo } from "@/stores/userinfo"
|
||||||
import { useEditor } from "@/stores/editor"
|
|
||||||
import ArticleContent from "@/components/posts/ArticleContent.vue"
|
import ArticleContent from "@/components/posts/ArticleContent.vue"
|
||||||
import MomentContent from "@/components/posts/MomentContent.vue"
|
import MomentContent from "@/components/posts/MomentContent.vue"
|
||||||
import CommentContent from "@/components/posts/CommentContent.vue"
|
import CommentContent from "@/components/posts/CommentContent.vue"
|
||||||
import PostAttachment from "./PostAttachment.vue"
|
import PostAttachment from "@/components/posts/PostAttachment.vue"
|
||||||
import PostReaction from "@/components/posts/PostReaction.vue"
|
import PostReaction from "@/components/posts/PostReaction.vue"
|
||||||
|
import PostAction from "@/components/posts/PostAction.vue"
|
||||||
|
|
||||||
const id = useUserinfo()
|
const id = useUserinfo()
|
||||||
|
|
||||||
const props = defineProps<{ item: any; brief?: boolean }>()
|
const props = defineProps<{ item: any; brief?: boolean }>()
|
||||||
const emits = defineEmits(["update:item"])
|
const emits = defineEmits(["update:item"])
|
||||||
|
|
||||||
const editor = useEditor()
|
|
||||||
|
|
||||||
const renderer: { [id: string]: Component } = {
|
const renderer: { [id: string]: Component } = {
|
||||||
article: ArticleContent,
|
article: ArticleContent,
|
||||||
moment: MomentContent,
|
moment: MomentContent,
|
||||||
comment: CommentContent
|
comment: CommentContent
|
||||||
}
|
}
|
||||||
|
|
||||||
const isOwned = computed(() => props.item?.author_id === id.userinfo.data.id)
|
|
||||||
|
|
||||||
function editPost() {
|
|
||||||
editor.related.edit_to = props.item
|
|
||||||
if (editor.show.hasOwnProperty(props.item.model_type)) {
|
|
||||||
// @ts-ignore
|
|
||||||
editor.show[props.item.model_type] = true
|
|
||||||
}
|
|
||||||
if (props.item.model_type === "comment") {
|
|
||||||
editor.related.comment_to = props.item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function deletePost() {
|
|
||||||
editor.related.delete_to = JSON.parse(JSON.stringify(props.item))
|
|
||||||
editor.related.delete_to.model_type = props.item.model_type + "s"
|
|
||||||
editor.show.delete = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateReactions(symbol: string, num: number) {
|
function updateReactions(symbol: string, num: number) {
|
||||||
const item = JSON.parse(JSON.stringify(props.item))
|
const item = JSON.parse(JSON.stringify(props.item))
|
||||||
if (item.reaction_list == null) {
|
if (item.reaction_list == null) {
|
||||||
|
71
pkg/views/src/components/realms/RealmEditor.vue
Normal file
71
pkg/views/src/components/realms/RealmEditor.vue
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<template>
|
||||||
|
<v-dialog :model-value="props.show" @update:model-value="(val) => emits('update:show', val)" class="max-w-[540px]">
|
||||||
|
<v-card title="Organize a realm" prepend-icon="mdi-account-multiple" :loading="loading">
|
||||||
|
<v-form @submit.prevent="submit">
|
||||||
|
<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-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
|
||||||
|
<v-btn type="reset" color="grey-darken-3" @click="emits('update:show', false)">Cancel</v-btn>
|
||||||
|
<v-btn type="submit" :disabled="loading">Save</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-form>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue"
|
||||||
|
import { getAtk } from "@/stores/userinfo"
|
||||||
|
|
||||||
|
const props = defineProps<{ show: boolean }>()
|
||||||
|
const emits = defineEmits(["update:show", "relist"])
|
||||||
|
|
||||||
|
const realmTypeOptions = [
|
||||||
|
{ label: "Public Realm", value: 0 },
|
||||||
|
{ label: "Restricted Realm", value: 1 },
|
||||||
|
{ label: "Private Realm", value: 2 }
|
||||||
|
]
|
||||||
|
|
||||||
|
const error = ref<null | string>(null)
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
const data = ref({
|
||||||
|
name: "",
|
||||||
|
description: "",
|
||||||
|
realm_type: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
async function submit(evt: SubmitEvent) {
|
||||||
|
const form = evt.target as HTMLFormElement
|
||||||
|
const payload = data.value
|
||||||
|
if (!payload.name) return
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
const res = await fetch("/api/realms", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${getAtk()}` },
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
})
|
||||||
|
if (res.status !== 200) {
|
||||||
|
error.value = await res.text()
|
||||||
|
} else {
|
||||||
|
emits("relist")
|
||||||
|
form.reset()
|
||||||
|
emits("update:show", false)
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
</script>
|
@ -2,11 +2,7 @@
|
|||||||
<v-list density="comfortable">
|
<v-list density="comfortable">
|
||||||
<v-list-subheader>
|
<v-list-subheader>
|
||||||
Realms
|
Realms
|
||||||
<v-badge
|
<v-badge color="warning" content="Alpha" inline />
|
||||||
color="warning"
|
|
||||||
content="Alpha"
|
|
||||||
inline
|
|
||||||
/>
|
|
||||||
</v-list-subheader>
|
</v-list-subheader>
|
||||||
|
|
||||||
<v-list-item
|
<v-list-item
|
||||||
@ -27,101 +23,35 @@
|
|||||||
/>
|
/>
|
||||||
</v-list>
|
</v-list>
|
||||||
|
|
||||||
<v-dialog v-model="creating" class="max-w-[540px]">
|
<realm-editor v-model:show="creating" @relist="list" />
|
||||||
<v-card title="Create a realm" prepend-icon="mdi-account-multiple-plus" :loading="loading">
|
|
||||||
<v-form @submit.prevent="submit">
|
|
||||||
<v-card-text>
|
|
||||||
<v-text-field
|
|
||||||
label="Name"
|
|
||||||
variant="outlined"
|
|
||||||
density="comfortable"
|
|
||||||
v-model="requestData.name"
|
|
||||||
/>
|
|
||||||
<v-textarea
|
|
||||||
label="Description"
|
|
||||||
variant="outlined"
|
|
||||||
density="comfortable"
|
|
||||||
v-model="requestData.description"
|
|
||||||
/>
|
|
||||||
<v-select
|
|
||||||
label="Realm type"
|
|
||||||
item-title="label"
|
|
||||||
item-value="value"
|
|
||||||
variant="outlined"
|
|
||||||
density="comfortable"
|
|
||||||
:items="realmTypeOptions"
|
|
||||||
v-model="requestData.realm_type"
|
|
||||||
/>
|
|
||||||
</v-card-text>
|
|
||||||
<v-card-actions>
|
|
||||||
<v-spacer></v-spacer>
|
|
||||||
|
|
||||||
<v-btn type="reset" color="grey-darken-3" @click="creating = false">Cancel</v-btn>
|
|
||||||
<v-btn type="submit" :disabled="loading">Save</v-btn>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-form>
|
|
||||||
</v-card>
|
|
||||||
</v-dialog>
|
|
||||||
|
|
||||||
<!-- @vue-ignore -->
|
<!-- @vue-ignore -->
|
||||||
<v-snackbar v-model="error" :timeout="5000">Something went wrong... {{ error }}</v-snackbar>
|
<v-snackbar v-model="error" :timeout="5000">Something went wrong... {{ error }}</v-snackbar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue"
|
||||||
import { getAtk, useUserinfo } from "@/stores/userinfo";
|
import { useUserinfo } from "@/stores/userinfo"
|
||||||
import { useEditor } from "@/stores/editor";
|
import { useEditor } from "@/stores/editor"
|
||||||
|
import RealmEditor from "@/components/realms/RealmEditor.vue"
|
||||||
|
|
||||||
const id = useUserinfo();
|
const id = useUserinfo()
|
||||||
const editor = useEditor();
|
const editor = useEditor()
|
||||||
|
|
||||||
const realms = computed(() => editor.availableRealms);
|
const realms = computed(() => editor.availableRealms)
|
||||||
const requestData = ref({
|
|
||||||
name: "",
|
|
||||||
description: "",
|
|
||||||
realm_type: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
const realmTypeOptions = [
|
const creating = ref(false)
|
||||||
{ label: "Public Realm", value: 0 },
|
|
||||||
{ label: "Restricted Realm", value: 1 },
|
|
||||||
{ label: "Private Realm", value: 2 }
|
|
||||||
];
|
|
||||||
|
|
||||||
const creating = ref(false);
|
const error = ref<string | null>(null)
|
||||||
|
const reverting = ref(false)
|
||||||
const error = ref<string | null>(null);
|
|
||||||
const reverting = ref(false);
|
|
||||||
const loading = ref(false);
|
|
||||||
|
|
||||||
async function list() {
|
async function list() {
|
||||||
reverting.value = true;
|
reverting.value = true
|
||||||
try {
|
try {
|
||||||
await editor.listRealms();
|
await editor.listRealms()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error.value = (err as Error).message;
|
error.value = (err as Error).message
|
||||||
}
|
}
|
||||||
reverting.value = false;
|
reverting.value = false
|
||||||
}
|
|
||||||
|
|
||||||
async function submit(evt: SubmitEvent) {
|
|
||||||
const form = evt.target as HTMLFormElement;
|
|
||||||
const payload = requestData.value;
|
|
||||||
if (!payload.name) return;
|
|
||||||
|
|
||||||
loading.value = true;
|
|
||||||
const res = await fetch("/api/realms", {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json", Authorization: `Bearer ${getAtk()}` },
|
|
||||||
body: JSON.stringify(payload)
|
|
||||||
});
|
|
||||||
if (res.status !== 200) {
|
|
||||||
error.value = await res.text();
|
|
||||||
} else {
|
|
||||||
await list();
|
|
||||||
form.reset();
|
|
||||||
creating.value = false;
|
|
||||||
}
|
|
||||||
loading.value = false;
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia"
|
||||||
import { reactive, ref } from "vue";
|
import { reactive, ref } from "vue"
|
||||||
import { checkLoggedIn, 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,24 +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
|
||||||
});
|
})
|
||||||
|
|
||||||
const availableRealms = ref<any[]>([]);
|
const availableRealms = ref<any[]>([])
|
||||||
|
|
||||||
async function listRealms() {
|
async function listRealms() {
|
||||||
if (!checkLoggedIn()) return;
|
if (!checkLoggedIn()) return
|
||||||
|
|
||||||
const res = await fetch("/api/realms/me/available", {
|
const res = await fetch("/api/realms/me/available", {
|
||||||
headers: { Authorization: `Bearer ${getAtk()}` }
|
headers: { Authorization: `Bearer ${getAtk()}` }
|
||||||
});
|
})
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
throw new Error(await res.text());
|
throw new Error(await res.text())
|
||||||
} else {
|
} else {
|
||||||
availableRealms.value = await res.json();
|
availableRealms.value = await res.json()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
listRealms().then(() => console.log("[STARTUP HOOK] Fetch available realm successes."));
|
listRealms().then(() => console.log("[STARTUP HOOK] Fetch available realm successes."))
|
||||||
|
|
||||||
return { show, related, availableRealms, listRealms, done };
|
return { show, related, availableRealms, listRealms, done }
|
||||||
});
|
})
|
||||||
|
@ -4,11 +4,17 @@
|
|||||||
<v-card :loading="loading">
|
<v-card :loading="loading">
|
||||||
<article>
|
<article>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<div class="px-3">
|
<div class="flex justify-between px-3">
|
||||||
|
<div>
|
||||||
<h1 class="text-lg font-medium">{{ post?.title }}</h1>
|
<h1 class="text-lg font-medium">{{ post?.title }}</h1>
|
||||||
<p class="text-sm">{{ post?.description }}</p>
|
<p class="text-sm">{{ post?.description }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<post-action :item="post" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<v-divider class="my-5 mx-[-16px] border-opacity-50" />
|
<v-divider class="my-5 mx-[-16px] border-opacity-50" />
|
||||||
|
|
||||||
<div class="px-3 text-xs opacity-80 flex gap-1">
|
<div class="px-3 text-xs opacity-80 flex gap-1">
|
||||||
@ -56,11 +62,12 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue"
|
import { ref } from "vue"
|
||||||
|
import { useRoute } from "vue-router"
|
||||||
import { request } from "@/scripts/request"
|
import { request } from "@/scripts/request"
|
||||||
import ArticleContent from "@/components/posts/ArticleContent.vue"
|
import ArticleContent from "@/components/posts/ArticleContent.vue"
|
||||||
import PostReaction from "@/components/posts/PostReaction.vue"
|
import PostReaction from "@/components/posts/PostReaction.vue"
|
||||||
|
import PostAction from "@/components/posts/PostAction.vue"
|
||||||
import CommentList from "@/components/comments/CommentList.vue"
|
import CommentList from "@/components/comments/CommentList.vue"
|
||||||
import { useRoute } from "vue-router"
|
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const error = ref<string | null>(null)
|
const error = ref<string | null>(null)
|
||||||
|
@ -4,11 +4,12 @@
|
|||||||
<v-card :loading="loading">
|
<v-card :loading="loading">
|
||||||
<article>
|
<article>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<div class="flex gap-2">
|
<div class="flex justify-between px-3">
|
||||||
|
<div class="flex gap-1">
|
||||||
<v-avatar
|
<v-avatar
|
||||||
color="grey-lighten-2"
|
color="grey-lighten-2"
|
||||||
icon="mdi-account-circle"
|
icon="mdi-account-circle"
|
||||||
class="rounded-card"
|
class="rounded-card me-2"
|
||||||
:image="post?.author.avatar"
|
:image="post?.author.avatar"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -20,6 +21,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<post-action :item="post" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<v-divider class="mb-5 mt-3.5 mx-[-16px] border-opacity-50" />
|
<v-divider class="mb-5 mt-3.5 mx-[-16px] border-opacity-50" />
|
||||||
|
|
||||||
<div class="px-3">
|
<div class="px-3">
|
||||||
@ -69,6 +75,7 @@ import MomentContent from "@/components/posts/MomentContent.vue"
|
|||||||
import PostReaction from "@/components/posts/PostReaction.vue"
|
import PostReaction from "@/components/posts/PostReaction.vue"
|
||||||
import CommentList from "@/components/comments/CommentList.vue"
|
import CommentList from "@/components/comments/CommentList.vue"
|
||||||
import PostAttachment from "@/components/posts/PostAttachment.vue"
|
import PostAttachment from "@/components/posts/PostAttachment.vue"
|
||||||
|
import PostAction from "@/components/posts/PostAction.vue"
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const error = ref<string | null>(null)
|
const error = ref<string | null>(null)
|
||||||
|
Loading…
Reference in New Issue
Block a user