main
parent
f6857712a8
commit
1c6e06bd6d
|
@ -0,0 +1,371 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import MDEditor, { commands } from '@uiw/react-md-editor';
|
||||
import { Card } from "./ui/card";
|
||||
import { Label } from "./ui/label";
|
||||
import { Button } from "./ui/button";
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "./ui/dialog";
|
||||
import { Input } from "./ui/input";
|
||||
import { useIsLoggedIn } from '../lib/isLoggedIn';
|
||||
|
||||
const COMMENTS_API_URL = 'https://host-api.cs1.hz.siliconpin.com/v1/comments/';
|
||||
const MINIO_UPLOAD_URL = 'https://hostapi2.cs1.hz.siliconpin.com/api/storage/upload';
|
||||
|
||||
export default function Comment(props) {
|
||||
const [comments, setComments] = useState([]);
|
||||
const [newComment, setNewComment] = useState({ comment: '' });
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [submitSuccess, setSubmitSuccess] = useState(false);
|
||||
const [submitError, setSubmitError] = useState('');
|
||||
const [isLoadingComments, setIsLoadingComments] = useState(true);
|
||||
const [editorMode, setEditorMode] = useState('edit');
|
||||
const [imageDialogOpen, setImageDialogOpen] = useState(false);
|
||||
const [imageUrlInput, setImageUrlInput] = useState('');
|
||||
const [imageUploadFile, setImageUploadFile] = useState(null);
|
||||
const [imageUploadPreview, setImageUploadPreview] = useState('');
|
||||
const [uploadProgress, setUploadProgress] = useState(0);
|
||||
const { isLoggedIn, loading, error, sessionData } = useIsLoggedIn();
|
||||
|
||||
// Custom image command for MDEditor
|
||||
const customImageCommand = {
|
||||
name: 'image',
|
||||
keyCommand: 'image',
|
||||
buttonProps: { 'aria-label': 'Insert image' },
|
||||
icon: (
|
||||
<svg width="12" height="12" viewBox="0 0 20 20">
|
||||
<path fill="currentColor" d="M15 9c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm4-7H1c-.55 0-1 .45-1 1v14c0 .55.45 1 1 1h18c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1zm-1 13l-6-5-2 2-4-5-4 8V4h16v11z"/>
|
||||
</svg>
|
||||
),
|
||||
execute: () => {
|
||||
setImageDialogOpen(true);
|
||||
},
|
||||
};
|
||||
|
||||
// Get all default commands and replace the image command
|
||||
const allCommands = commands.getCommands().map(cmd => {
|
||||
if (cmd.name === 'image') {
|
||||
return customImageCommand;
|
||||
}
|
||||
return cmd;
|
||||
});
|
||||
|
||||
// Load comments when component mounts
|
||||
useEffect(() => {
|
||||
if (props.topicId) {
|
||||
fetchComments(props.topicId);
|
||||
}
|
||||
}, [props.topicId]);
|
||||
|
||||
const fetchComments = async (topicId) => {
|
||||
setIsLoadingComments(true);
|
||||
try {
|
||||
const response = await fetch(`${COMMENTS_API_URL}?topicId=${topicId}`, {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
if (!response.ok) {
|
||||
throw new Error(data.message || 'Failed to fetch comments');
|
||||
}
|
||||
|
||||
if (data.success && data.comments) {
|
||||
setComments(data.comments);
|
||||
} else {
|
||||
throw new Error('Invalid response format');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching comments:', error);
|
||||
setSubmitError('Failed to load comments');
|
||||
} finally {
|
||||
setIsLoadingComments(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Upload file to MinIO
|
||||
const uploadToMinIO = async (file) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('api_key', 'wweifwehfwfhwhtuyegbvijvbfvegfreyf');
|
||||
|
||||
try {
|
||||
const response = await fetch(MINIO_UPLOAD_URL, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Upload failed');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data.publicUrl;
|
||||
} catch (error) {
|
||||
console.error('Upload error:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Handle image URL insertion
|
||||
const handleInsertImageUrl = () => {
|
||||
if (imageUrlInput) {
|
||||
const imgMarkdown = ``;
|
||||
setNewComment(prev => ({
|
||||
...prev,
|
||||
comment: prev.comment ? `${prev.comment}\n${imgMarkdown}` : imgMarkdown
|
||||
}));
|
||||
setImageDialogOpen(false);
|
||||
setImageUrlInput('');
|
||||
}
|
||||
};
|
||||
|
||||
// Handle image file selection
|
||||
const handleImageFileSelect = (e) => {
|
||||
const file = e.target.files[0];
|
||||
if (file) {
|
||||
setImageUploadFile(file);
|
||||
|
||||
// Create preview
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
setImageUploadPreview(reader.result);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
};
|
||||
|
||||
// Upload image file to MinIO and insert into editor
|
||||
const handleImageUpload = async () => {
|
||||
if (!imageUploadFile) return;
|
||||
|
||||
try {
|
||||
setIsSubmitting(true);
|
||||
setUploadProgress(0);
|
||||
|
||||
const uploadedUrl = await uploadToMinIO(imageUploadFile);
|
||||
|
||||
// Insert markdown for the uploaded image
|
||||
const imgMarkdown = ``;
|
||||
setNewComment(prev => ({
|
||||
...prev,
|
||||
comment: prev.comment ? `${prev.comment}\n${imgMarkdown}` : imgMarkdown
|
||||
}));
|
||||
|
||||
setImageDialogOpen(false);
|
||||
setImageUploadFile(null);
|
||||
setImageUploadPreview('');
|
||||
} catch (error) {
|
||||
setSubmitError('Failed to upload image: ' + error.message);
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmitComment = async (e) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
setSubmitError('');
|
||||
|
||||
try {
|
||||
const response = await fetch(`${COMMENTS_API_URL}?query=new-comment`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
...newComment,
|
||||
topicId: props.topicId
|
||||
}),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
setNewComment({ comment: '' });
|
||||
setSubmitSuccess(true);
|
||||
setTimeout(() => setSubmitSuccess(false), 3000);
|
||||
|
||||
// Refresh comments after successful submission
|
||||
await fetchComments(props.topicId);
|
||||
} else {
|
||||
const errorData = await response.json();
|
||||
setSubmitError(errorData.message || 'Failed to submit comment');
|
||||
}
|
||||
} catch (error) {
|
||||
setSubmitError('Network error. Please try again.');
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const getUserInitials = (name) => {
|
||||
if (!name) return 'U';
|
||||
const words = name.trim().split(' ');
|
||||
return words
|
||||
.slice(0, 2)
|
||||
.map(word => word[0].toUpperCase())
|
||||
.join('');
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Comments List */}
|
||||
<div className="space-y-6 border-t">
|
||||
<h2 className="text-2xl font-bold text-[#6d9e37]">Comments ({comments.length})</h2>
|
||||
|
||||
{isLoadingComments ? (
|
||||
<div className="flex justify-center py-4">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-[#6d9e37]"></div>
|
||||
</div>
|
||||
) : comments.length === 0 ? (
|
||||
<p className="text-gray-500">No comments yet. Be the first to comment!</p>
|
||||
) : (
|
||||
comments.map(comment => (
|
||||
<div key={comment.id} className="border-b pb-6 last:border-b-0">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="flex-shrink-0">
|
||||
<div className="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center text-gray-500 font-bold">
|
||||
{getUserInitials(comment.userName)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<h4 className="font-medium text-[#6d9e37]">
|
||||
{comment.userName || 'User'}
|
||||
</h4>
|
||||
<span className="text-xs text-gray-500">
|
||||
{new Date(comment.created_at).toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
<div data-color-mode="light" className="markdown-body">
|
||||
<MDEditor.Markdown source={comment.comment} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Comments Section with MDEditor */}
|
||||
<Card className="mt-16 border-t">
|
||||
<div className="relative">
|
||||
<div className="px-6 pb-6 rounded-lg">
|
||||
<h3 className="text-lg font-medium mb-4 pt-8">Leave a Comment</h3>
|
||||
{submitSuccess && (
|
||||
<div className="mb-4 p-3 bg-green-100 text-green-700 rounded">
|
||||
Thank you for your comment!
|
||||
</div>
|
||||
)}
|
||||
{submitError && (
|
||||
<div className="mb-4 p-3 bg-red-100 text-red-700 rounded">
|
||||
{submitError}
|
||||
</div>
|
||||
)}
|
||||
<form onSubmit={handleSubmitComment}>
|
||||
<div className="mb-4">
|
||||
<Label htmlFor="comment">Comment *</Label>
|
||||
<div data-color-mode="light">
|
||||
<MDEditor
|
||||
placeholder="Write your comment (markdown supported)"
|
||||
value={newComment.comment}
|
||||
onChange={(value) => setNewComment(prev => ({ ...prev, comment: value || '' }))}
|
||||
height={300}
|
||||
preview={editorMode}
|
||||
commands={allCommands}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-end mt-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setEditorMode(editorMode === 'edit' ? 'preview' : 'edit')}
|
||||
className={`text-sm ${editorMode !== 'edit' ? 'bg-[#6d9e37] text-white' : 'text-[#6d9e37]'} px-2 py-1 rounded-md border border-[#6d9e37]`}
|
||||
>
|
||||
{editorMode === 'edit' ? 'Preview' : 'Edit'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<Button type="submit" disabled={isSubmitting || !isLoggedIn}>
|
||||
{isSubmitting ? 'Submitting...' : 'Post Comment'}
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{/* Image Upload Dialog */}
|
||||
<Dialog open={imageDialogOpen} onOpenChange={setImageDialogOpen}>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Insert Image</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="grid gap-4 py-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="image-url">From URL</Label>
|
||||
<Input
|
||||
id="image-url"
|
||||
type="text"
|
||||
placeholder="Enter image URL"
|
||||
value={imageUrlInput}
|
||||
onChange={(e) => setImageUrlInput(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={handleInsertImageUrl}
|
||||
disabled={!imageUrlInput}
|
||||
className="mt-2"
|
||||
>
|
||||
Insert Image
|
||||
</Button>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="image-upload">Upload Image</Label>
|
||||
<Input
|
||||
id="image-upload"
|
||||
type="file"
|
||||
accept="image/*"
|
||||
onChange={handleImageFileSelect}
|
||||
/>
|
||||
{imageUploadPreview && (
|
||||
<div className="mt-2">
|
||||
<img
|
||||
src={imageUploadPreview}
|
||||
alt="Preview"
|
||||
className="max-h-40 rounded-md border"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<Button
|
||||
type="button"
|
||||
onClick={handleImageUpload}
|
||||
disabled={!imageUploadFile || isSubmitting}
|
||||
className="mt-2"
|
||||
>
|
||||
{isSubmitting ? 'Uploading...' : 'Upload & Insert'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{loading ? (
|
||||
<>
|
||||
<div className="w-full h-full absolute bg-black inset-0 opacity-70 backdrop-blur-2xl rounded-lg" />
|
||||
<div className="w-10 h-10 rounded-full border-2 border-dotted border-[#6d9e37] absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2" role="status">
|
||||
<span className="sr-only">Loading...</span>
|
||||
</div>
|
||||
</>
|
||||
) : !isLoggedIn ? (
|
||||
<>
|
||||
<div className="w-full h-full absolute bg-black inset-0 opacity-70 backdrop-blur-2xl rounded-lg" />
|
||||
<p className="text-gray-100 bg-gray-700 p-2 rounded-md shadow-xl italic absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
|
||||
Join the conversation! Log in or sign up to post a comment
|
||||
</p>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Card } from "./ui/card";
|
||||
import { Label } from "./ui/label";
|
||||
import { Textarea } from "./ui/textarea";
|
||||
import { Button } from "./ui/button";
|
||||
import { useIsLoggedIn } from '../lib/isLoggedIn';
|
||||
|
||||
const COMMENTS_API_URL = 'https://host-api.cs1.hz.siliconpin.com/v1/comments/';
|
||||
|
||||
export default function Comment(props) {
|
||||
const [comments, setComments] = useState([]);
|
||||
const [newComment, setNewComment] = useState({ comment: '' });
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [submitSuccess, setSubmitSuccess] = useState(false);
|
||||
const [submitError, setSubmitError] = useState('');
|
||||
const [isLoadingComments, setIsLoadingComments] = useState(true);
|
||||
const { isLoggedIn, loading, error, sessionData } = useIsLoggedIn();
|
||||
|
||||
// Load comments when component mounts or when topicId changes
|
||||
useEffect(() => {
|
||||
if (props.topicId) {
|
||||
fetchComments(props.topicId);
|
||||
}
|
||||
}, [props.topicId]);
|
||||
|
||||
const fetchComments = async (topicId) => {
|
||||
setIsLoadingComments(true);
|
||||
try {
|
||||
const response = await fetch(`${COMMENTS_API_URL}?topicId=${topicId}`, {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
if (!response.ok) {
|
||||
throw new Error(data.message || 'Failed to fetch comments');
|
||||
}
|
||||
|
||||
if (data.success && data.comments) {
|
||||
setComments(data.comments);
|
||||
} else {
|
||||
throw new Error('Invalid response format');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching comments:', error);
|
||||
setSubmitError('Failed to load comments');
|
||||
} finally {
|
||||
setIsLoadingComments(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleInputChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setNewComment(prev => ({
|
||||
...prev,
|
||||
[name]: value
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSubmitComment = async (e) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
setSubmitError('');
|
||||
|
||||
try {
|
||||
const response = await fetch(`${COMMENTS_API_URL}?query=new-comment`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
...newComment,
|
||||
topicId: props.topicId
|
||||
}),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
setNewComment({ comment: '' });
|
||||
setSubmitSuccess(true);
|
||||
setTimeout(() => setSubmitSuccess(false), 3000);
|
||||
|
||||
// Refresh comments after successful submission
|
||||
await fetchComments(props.topicId);
|
||||
} else {
|
||||
const errorData = await response.json();
|
||||
setSubmitError(errorData.message || 'Failed to submit comment');
|
||||
}
|
||||
} catch (error) {
|
||||
setSubmitError('Network error. Please try again.');
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const getUserInitials = (name) => {
|
||||
if (!name) return 'U';
|
||||
const words = name.trim().split(' ');
|
||||
return words
|
||||
.slice(0, 2)
|
||||
.map(word => word[0].toUpperCase())
|
||||
.join('');
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Comments List */}
|
||||
<div className="space-y-6 border-t">
|
||||
<h2 className="text-2xl font-bold text-[#6d9e37]">Comments ({comments.length})</h2>
|
||||
|
||||
{isLoadingComments ? (
|
||||
<div className="flex justify-center py-4">
|
||||
{/* <div className="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-[#6d9e37]"></div> */}
|
||||
</div>
|
||||
) : comments.length === 0 ? (
|
||||
<p className="text-gray-500">No comments yet. Be the first to comment!</p>
|
||||
) : (
|
||||
comments.map(comment => (
|
||||
<div key={comment.id} className="border-b pb-6 last:border-b-0">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="flex-shrink-0">
|
||||
<div className="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center text-gray-500 font-bold">
|
||||
{getUserInitials(comment.userName)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<h4 className="font-medium text-[#6d9e37]">
|
||||
{comment.userName || 'User'}
|
||||
</h4>
|
||||
<span className="text-xs text-gray-500">
|
||||
{new Date(comment.created_at).toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
<p className="">{comment.comment}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Comments Section */}
|
||||
<Card className="mt-16 border-t">
|
||||
<div className="relative">
|
||||
<div className="px-6 pb-6 rounded-lg">
|
||||
<h3 className="text-lg font-medium mb-4 pt-8">Leave a Comment</h3>
|
||||
{submitSuccess && (
|
||||
<div className="mb-4 p-3 bg-green-100 text-green-700 rounded">
|
||||
Thank you for your comment!
|
||||
</div>
|
||||
)}
|
||||
{submitError && (
|
||||
<div className="mb-4 p-3 bg-red-100 text-red-700 rounded">
|
||||
{submitError}
|
||||
</div>
|
||||
)}
|
||||
<form onSubmit={handleSubmitComment}>
|
||||
<div className="mb-4">
|
||||
<Label htmlFor="comment">Comment *</Label>
|
||||
<Textarea
|
||||
className="mt-2"
|
||||
id="comment"
|
||||
name="comment"
|
||||
rows="4"
|
||||
value={newComment.comment}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
disabled={!isLoggedIn}
|
||||
/>
|
||||
</div>
|
||||
<Button type="submit" disabled={isSubmitting || !isLoggedIn}>
|
||||
{isSubmitting ? 'Submitting...' : 'Post Comment'}
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
{loading ? (
|
||||
<>
|
||||
<div className="w-full h-full absolute bg-black inset-0 opacity-70 backdrop-blur-2xl rounded-lg" />
|
||||
<div className="w-10 h-10 rounded-full border-2 border-dotted border-[#6d9e37] absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2" role="status">
|
||||
<span className="sr-only">Loading...</span>
|
||||
</div>
|
||||
</>
|
||||
) : !isLoggedIn ? (
|
||||
<>
|
||||
<div className="w-full h-full absolute bg-black inset-0 opacity-70 backdrop-blur-2xl rounded-lg" />
|
||||
<p className="text-gray-100 bg-gray-700 p-2 rounded-md shadow-xl italic absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
|
||||
Join the conversation! Log in or sign up to post a comment
|
||||
</p>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -1,6 +1,12 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { marked } from 'marked';
|
||||
|
||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "./ui/card";
|
||||
import { Label } from "./ui/label";
|
||||
import { Textarea } from "./ui/textarea";
|
||||
import { Button } from "./ui/button";
|
||||
import { useIsLoggedIn } from '../lib/isLoggedIn';
|
||||
import Comment from './Comment';
|
||||
const COMMENTS_API_URL = 'https://host-api.cs1.hz.siliconpin.com/v1/comments/';
|
||||
export default function TopicDetail(props) {
|
||||
const [showCopied, setShowCopied] = useState(false);
|
||||
|
||||
|
@ -12,31 +18,6 @@ export default function TopicDetail(props) {
|
|||
const title = props.topic.title;
|
||||
const text = `Check out this article: ${title}`;
|
||||
|
||||
// const shareOnFacebook = () => {
|
||||
// window.open(`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(shareUrl)}`, '_blank');
|
||||
// };
|
||||
|
||||
// const shareOnTwitter = () => {
|
||||
// window.open(`https://twitter.com/intent/tweet?url=${encodeURIComponent(shareUrl)}&text=${encodeURIComponent(text)}`, '_blank');
|
||||
// };
|
||||
|
||||
// const shareOnLinkedIn = () => {
|
||||
// window.open(`https://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(shareUrl)}&title=${encodeURIComponent(title)}`, '_blank');
|
||||
// };
|
||||
|
||||
// const shareOnReddit = () => {
|
||||
// window.open(`https://www.reddit.com/submit?url=${encodeURIComponent(shareUrl)}&title=${encodeURIComponent(title)}`, '_blank');
|
||||
// };
|
||||
|
||||
// const shareOnWhatsApp = () => {
|
||||
// window.open(`https://wa.me/?text=${encodeURIComponent(`${text} ${shareUrl}`)}`, '_blank');
|
||||
// };
|
||||
|
||||
// const shareViaEmail = () => {
|
||||
// window.open(`mailto:?subject=${encodeURIComponent(title)}&body=${encodeURIComponent(`${text}\n\n${shareUrl}`)}`);
|
||||
// };
|
||||
|
||||
|
||||
const shareOnSocialMedia = (platform) => {
|
||||
switch (platform){
|
||||
case 'facebook':
|
||||
|
@ -211,11 +192,11 @@ export default function TopicDetail(props) {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="font-light mb-8 text-justify prose max-w-none"
|
||||
dangerouslySetInnerHTML={{ __html: marked.parse(props.topic.content || '') }}
|
||||
></div>
|
||||
<div className="font-light mb-8 text-justify prose max-w-none" dangerouslySetInnerHTML={{ __html: marked.parse(props.topic.content || '') }} ></div>
|
||||
<Comment topicId={props.topic.id}/>
|
||||
</article>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// bg-[#6d9e37]
|
Loading…
Reference in New Issue