Created
August 16, 2024 08:54
-
-
Save dmdboi/21447b8513e353e2c5a8e26c71a9e18a to your computer and use it in GitHub Desktop.
A vue compnent example for adding Headless Comments to your website
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import axios from "axios"; | |
const API_TOKEN = ""; | |
const SITE_ID = ""; | |
const api = axios.create({ | |
baseURL: "https://headlesscomments.io/api/", | |
headers: { | |
"Content-type": "application/json", | |
Authorization: `Bearer ${API_TOKEN}`, | |
"x-site-id": SITE_ID, | |
}, | |
}); | |
export default class Comments { | |
headers(slug: string) { | |
return { | |
headers: { | |
"x-slug": slug, | |
}, | |
}; | |
} | |
async getPageComments(slug: string) { | |
return (await api.get(`/comments?page=${slug}`, this.headers(slug))).data; | |
} | |
async postComment(slug: string, data: CreateCommentRequest) { | |
return await api.post(`/comments`, data, this.headers(slug)); | |
} | |
} | |
export interface CreateCommentRequest { | |
name: string; | |
email: string; | |
content: string; | |
parent_id?: string; | |
} | |
export interface Comment { | |
id: string; | |
author_name: string; | |
author_email: string; | |
content: string; | |
parent_id: string; | |
created_at: string; | |
children: Comment[]; | |
approved: boolean; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div> | |
<h2>Comments</h2> | |
<!-- Comments List --> | |
<ul v-if="isLoaded"> | |
<li v-for="comment in comments" :key="comment.id"> | |
<span>{{ comment.content }}</span> | |
<div> | |
<strong>{{ comment.author_name }}</strong> - | |
<span>{{ new Date(comment.created_at).toLocaleDateString() }}</span> | |
</div> | |
</li> | |
</ul> | |
<!-- Loading Spinner --> | |
<div v-else>Loading...</div> | |
<!-- Message Box --> | |
<div class="message-box"> | |
<form @submit.prevent="submit"> | |
<div class="author-info"> | |
<input type="text" placeholder="Name" v-model="comment.name" /> | |
<input type="email" placeholder="Email" v-model="comment.email" /> | |
</div> | |
<textarea rows="4" placeholder="Write your comment here..." v-model="comment.content"></textarea> | |
<div class="button-container"> | |
<button>Submit</button> | |
</div> | |
</form> | |
</div> | |
</div> | |
</template> | |
<script setup lang="ts"> | |
import { ref, onMounted } from "vue"; | |
import Comments from "../../comments"; | |
import type { Comment } from "../../comments"; | |
const hc = new Comments(); | |
const path = window.location.pathname.replace(/\/$/, ""); | |
const isLoaded = ref(false); | |
const isSending = ref(false); | |
const comments = ref([] as Comment[]); | |
const comment = ref({ | |
name: "", | |
email: "", | |
content: "", | |
}); | |
async function fetchComments() { | |
isLoaded.value = false; | |
comments.value = (await hc.getPageComments(path)).data; | |
isLoaded.value = true; | |
} | |
async function submit() { | |
isSending.value = true; | |
const response = await hc.postComment(path, comment.value); | |
if (response.status === 200) { | |
alert("Comment submitted successfully!"); | |
} else { | |
alert("Failed to submit comment. Please try again."); | |
} | |
// Clear the form | |
comment.value = { | |
name: "", | |
email: "", | |
content: "", | |
}; | |
comments.value = (await hc.getPageComments(path)).data; | |
isSending.value = false; | |
} | |
onMounted(async () => { | |
await fetchComments(); | |
}); | |
</script> | |
<style scoped> | |
ul { | |
list-style: none; | |
padding: 0; | |
} | |
li { | |
margin-bottom: 1rem; | |
padding: 1rem; | |
border: 1px solid #ccc; | |
} | |
.message-box { | |
margin-top: 1rem; | |
border: 1px solid #ccc; | |
padding: 1rem; | |
} | |
.message-box textarea { | |
margin-bottom: 0.5rem; | |
border-radius: 4px; | |
border: 1px solid #ccc; | |
resize: vertical; | |
} | |
.message-box .author-info { | |
display: grid; | |
gap: 0.5rem; | |
} | |
.author-info input { | |
margin-bottom: 0.5rem; | |
border-radius: 4px; | |
border: 1px solid #ccc; | |
padding: 0.5rem; | |
} | |
.button-container { | |
display: flex; | |
justify-content: flex-end; | |
} | |
.message-box button { | |
padding: 0.5rem 1rem; | |
background-color: #007bff; | |
color: white; | |
border: none; | |
cursor: pointer; | |
border-radius: 4px; | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment