♻️ Interactive v2 #1
| @@ -3,7 +3,7 @@ | ||||
|     <v-progress-circular indeterminate /> | ||||
|   </div> | ||||
|  | ||||
|   <div v-else class="flex flex-col gap-2 mt-3"> | ||||
|   <div v-else class="flex flex-col gap-5 mt-3"> | ||||
|     <div v-for="(item, idx) in props.comments" class="text-sm"> | ||||
|       <post-item :item="item" @update:item="(val) => updateItem(idx, val)" /> | ||||
|     </div> | ||||
|   | ||||
| @@ -47,7 +47,7 @@ | ||||
|         <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" /> | ||||
|           <v-list-item v-if="isOwned" append-icon="mdi-delete" title="Delete" @click="deletePost" /> | ||||
|         </v-list> | ||||
|       </v-menu> | ||||
|     </div> | ||||
| @@ -85,6 +85,15 @@ function editPost() { | ||||
|     // @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) { | ||||
|   | ||||
| @@ -21,7 +21,7 @@ | ||||
|  | ||||
|       <v-card-text> | ||||
|         <v-container class="article-container"> | ||||
|           <v-alert v-if="editor.related.edit_to" class="mb-3" type="info" variant="tonal"> | ||||
|           <v-alert v-if="editor.related.edit_to" class="mb-5" type="info" variant="tonal"> | ||||
|             You are editing a post with alias <b class="font-mono">{{ editor.related.edit_to?.alias }}</b> | ||||
|           </v-alert> | ||||
|  | ||||
|   | ||||
| @@ -2,7 +2,11 @@ | ||||
|   <v-card title="Leave your comment" :loading="loading"> | ||||
|     <v-form @submit.prevent="postComment"> | ||||
|       <v-card-text> | ||||
|         <v-textarea required hide-details name="content" variant="outlined" label="What do you want to say?" /> | ||||
|         <v-alert v-if="editor.related.edit_to" class="mb-5" type="info" variant="tonal"> | ||||
|           You are editing a comment with alias <b class="font-mono">{{ editor.related.edit_to?.alias }}</b> | ||||
|         </v-alert> | ||||
|  | ||||
|         <v-textarea required hide-details variant="outlined" label="What do you want to say?" v-model="data.content" /> | ||||
|  | ||||
|         <p class="px-2 mt-1 text-body-2 opacity-80">Your comment will leave below {{ postIdentifier }}</p> | ||||
|       </v-card-text> | ||||
| @@ -26,7 +30,7 @@ | ||||
| import { request } from "@/scripts/request" | ||||
| import { useEditor } from "@/stores/editor" | ||||
| import { getAtk } from "@/stores/userinfo" | ||||
| import { computed, ref } from "vue" | ||||
| import { computed, ref, watch } from "vue" | ||||
|  | ||||
| const editor = useEditor() | ||||
|  | ||||
| @@ -43,16 +47,26 @@ const error = ref<string | null>(null) | ||||
| const success = ref(false) | ||||
| const loading = ref(false) | ||||
|  | ||||
| const data = ref<any>({ | ||||
|   content: "" | ||||
| }) | ||||
|  | ||||
| async function postComment(evt: SubmitEvent) { | ||||
|   const form = evt.target as HTMLFormElement | ||||
|   const data = new FormData(form) | ||||
|   if (!data.has("content")) return | ||||
|   const payload = data.value | ||||
|  | ||||
|   if (!payload.content) return | ||||
|  | ||||
|   const url = editor.related.edit_to | ||||
|     ? `/api/p/comments/${editor.related.edit_to?.id}` | ||||
|     : `/api/p/${target.value?.model_type}/${target.value?.alias}/comments` | ||||
|   const method = editor.related.edit_to ? "PUT" : "POST" | ||||
|  | ||||
|   loading.value = true | ||||
|   const res = await request(`/api/p/${target.value?.model_type}/${target.value?.alias}/comments`, { | ||||
|     method: "POST", | ||||
|     headers: { Authorization: `Bearer ${getAtk()}` }, | ||||
|     body: data | ||||
|   const res = await request(url, { | ||||
|     method: method, | ||||
|     headers: { "Content-Type": "application/json", Authorization: `Bearer ${getAtk()}` }, | ||||
|     body: JSON.stringify(payload) | ||||
|   }) | ||||
|   if (res.status === 200) { | ||||
|     form.reset() | ||||
| @@ -64,4 +78,10 @@ async function postComment(evt: SubmitEvent) { | ||||
|   loading.value = false | ||||
|   editor.done = true | ||||
| } | ||||
|  | ||||
| watch(editor.related, (val) => { | ||||
|   if (val.edit_to && val.edit_to.model_type === "comment") { | ||||
|     data.value = val.edit_to | ||||
|   } | ||||
| }) | ||||
| </script> | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|   <v-card title="Record a moment" :loading="loading"> | ||||
|     <v-form @submit.prevent="postMoment"> | ||||
|       <v-card-text> | ||||
|         <v-alert v-if="editor.related.edit_to" class="mb-3" type="info" variant="tonal"> | ||||
|         <v-alert v-if="editor.related.edit_to" class="mb-5" type="info" variant="tonal"> | ||||
|           You are editing a post with alias <b class="font-mono">{{ editor.related.edit_to?.alias }}</b> | ||||
|         </v-alert> | ||||
|  | ||||
| @@ -117,7 +117,7 @@ async function postMoment(evt: SubmitEvent) { | ||||
| } | ||||
|  | ||||
| watch(editor.related, (val) => { | ||||
|   if (val.edit_to) { | ||||
|   if (val.edit_to && val.edit_to.model_type === "moment") { | ||||
|     data.value = val.edit_to | ||||
|   } | ||||
| }) | ||||
|   | ||||
| @@ -8,13 +8,18 @@ | ||||
|   <v-dialog v-model="editor.show.article" transition="dialog-bottom-transition" fullscreen eager> | ||||
|     <article-editor /> | ||||
|   </v-dialog> | ||||
|  | ||||
|   <v-dialog v-model="editor.show.delete" class="max-w-[540px]" eager> | ||||
|     <post-deletion /> | ||||
|   </v-dialog> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { useEditor } from "@/stores/editor" | ||||
| import MomentEditor from "@/components/publish/MomentEditor.vue" | ||||
| import CommentEditor from "@/components/publish/CommentEditor.vue"; | ||||
| import ArticleEditor from "@/components/publish/ArticleEditor.vue"; | ||||
| import CommentEditor from "@/components/publish/CommentEditor.vue" | ||||
| import ArticleEditor from "@/components/publish/ArticleEditor.vue" | ||||
| import PostDeletion from "@/components/publish/PostDeletion.vue" | ||||
|  | ||||
| const editor = useEditor() | ||||
| </script> | ||||
|   | ||||
							
								
								
									
										51
									
								
								pkg/views/src/components/publish/PostDeletion.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								pkg/views/src/components/publish/PostDeletion.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| <template> | ||||
|   <v-card title="Delete a post" :loading="loading"> | ||||
|     <template #text> | ||||
|       You are deleting a post with alias | ||||
|       <b class="font-mono">{{ editor.related.delete_to?.alias }}</b> | ||||
|       Are you confirm? | ||||
|     </template> | ||||
|     <template #actions> | ||||
|       <div class="w-full flex justify-end"> | ||||
|         <v-btn color="grey-darken-3" @click="editor.show.delete = false">Not really</v-btn> | ||||
|         <v-btn color="error" :disabled="loading" @click="deletePost">Yes</v-btn> | ||||
|       </div> | ||||
|     </template> | ||||
|   </v-card> | ||||
|  | ||||
|   <v-snackbar v-model="success" :timeout="3000">The post has been deleted.</v-snackbar> | ||||
|  | ||||
|   <!-- @vue-ignore --> | ||||
|   <v-snackbar v-model="error" :timeout="5000">Something went wrong... {{ error }}</v-snackbar> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { useEditor } from "@/stores/editor" | ||||
| import { getAtk } from "@/stores/userinfo" | ||||
| import { ref } from "vue" | ||||
|  | ||||
| const editor = useEditor() | ||||
|  | ||||
| const error = ref<string | null>(null) | ||||
| const success = ref(false) | ||||
| const loading = ref(false) | ||||
|  | ||||
| async function deletePost() { | ||||
|   const target = editor.related.delete_to | ||||
|   const url = `/api/p/${target.model_type}/${target.id}` | ||||
|  | ||||
|   loading.value = true | ||||
|   const res = await fetch(url, { | ||||
|     method: "DELETE", | ||||
|     headers: { Authorization: `Bearer ${getAtk()}` } | ||||
|   }) | ||||
|   if (res.status !== 200) { | ||||
|     error.value = await res.text() | ||||
|   } else { | ||||
|     success.value = true | ||||
|     editor.show.delete = false | ||||
|     editor.related.delete_to = null | ||||
|   } | ||||
|   loading.value = false | ||||
| } | ||||
| </script> | ||||
| @@ -1,5 +1,6 @@ | ||||
| import { defineStore } from "pinia" | ||||
| import { reactive, ref } from "vue" | ||||
| import { getAtk } from "@/stores/userinfo" | ||||
|  | ||||
| export const useEditor = defineStore("editor", () => { | ||||
|   const done = ref(false) | ||||
| @@ -7,14 +8,22 @@ export const useEditor = defineStore("editor", () => { | ||||
|   const show = reactive({ | ||||
|     moment: false, | ||||
|     article: false, | ||||
|     comment: false | ||||
|     comment: false, | ||||
|     delete: false | ||||
|   }) | ||||
|  | ||||
|   const related = reactive<{ edit_to: any; comment_to: any; reply_to: any; repost_to: any }>({ | ||||
|   const related = reactive<{ | ||||
|     edit_to: any | ||||
|     comment_to: any | ||||
|     reply_to: any | ||||
|     repost_to: any | ||||
|     delete_to: any | ||||
|   }>({ | ||||
|     edit_to: null, | ||||
|     comment_to: null, | ||||
|     reply_to: null, | ||||
|     repost_to: null | ||||
|     repost_to: null, | ||||
|     delete_to: null | ||||
|   }) | ||||
|  | ||||
|   return { show, related, done } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| <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"> | ||||
|     <div class="content flex-grow-1"> | ||||
|       <v-card :loading="loading"> | ||||
|         <article> | ||||
|           <v-card-text> | ||||
| @@ -26,7 +26,7 @@ | ||||
|       </v-card> | ||||
|     </div> | ||||
|  | ||||
|     <div class="aside sticky top-0 w-full h-fit md:max-w-[360px] md:min-w-[280px]"> | ||||
|     <div class="aside sticky top-0 w-full h-fit w-full md:max-w-[380px] md:min-w-[360px]"> | ||||
|       <v-card title="Comments"> | ||||
|         <div class="px-[1rem] pb-[0.825rem] mt-[-12px]"> | ||||
|           <comment-list | ||||
|   | ||||
		Reference in New Issue
	
	Block a user