From 9f2f235c092eabc27bed73cecc94f9bb1cba55c8 Mon Sep 17 00:00:00 2001 From: suvodip ghosh Date: Fri, 11 Jul 2025 06:49:12 +0000 Subject: [PATCH] add image gallery slider & emoji in topic singl page and othrs improvment --- package-lock.json | 22 ++ package.json | 1 + .../CommentSystem/CommentSystem.jsx | 193 ++++++++++++------ .../CommentSystem/CommentThread.jsx | 129 ++++++++++-- src/components/ImageSlider/ImageSlider.css | 56 +++++ src/components/ImageSlider/ImageSlider.jsx | 174 ++++++++++++++++ src/components/NewTopic.jsx | 62 +++--- src/components/TopicDetail.jsx | 24 ++- src/components/TopicEdit.jsx | 153 +++++++++++--- src/components/TopicItem.jsx | 2 +- src/layouts/Layout.astro | 30 +-- src/pages/about-us.astro | 1 + src/pages/contact.astro | 1 + src/pages/get-started.astro | 1 + src/pages/index.astro | 1 + src/pages/privacy-policy.astro | 1 + src/pages/profile/index.astro | 2 +- src/pages/services/buy-vpn.astro | 2 +- .../services/cloud-hetzner-instance.astro | 2 +- src/pages/services/cloud-instance.astro | 2 +- src/pages/services/create-droplets.astro | 2 +- src/pages/services/index.astro | 1 + src/pages/services/kubernetes.astro | 7 + src/pages/services/kubernetis.astro | 2 +- src/pages/services/stt-streaming.astro | 2 +- src/pages/topic/[id].astro | 33 ++- src/pages/topic/index.astro | 2 +- tailwind.config.mjs | 3 + yarn.lock | 12 ++ 29 files changed, 740 insertions(+), 183 deletions(-) create mode 100644 src/components/ImageSlider/ImageSlider.css create mode 100644 src/components/ImageSlider/ImageSlider.jsx create mode 100644 src/pages/services/kubernetes.astro diff --git a/package-lock.json b/package-lock.json index c30ca43..3cd031e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", + "emoji-picker-react": "^4.12.3", "framer-motion": "^12.18.1", "image-resize-compress": "^2.1.1", "js-cookie": "^3.0.5", @@ -6729,6 +6730,21 @@ "integrity": "sha512-oTUp3gfX1gZI+xfD2djr2rzQdHCwHzPQrrK0CD7WpTdF0nPdQ/INcRVjWgLdCT4a9W3jFObR9DAfsuyFQnI8CQ==", "license": "ISC" }, + "node_modules/emoji-picker-react": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/emoji-picker-react/-/emoji-picker-react-4.12.3.tgz", + "integrity": "sha512-Pf+pTenW/uM+Juw197dbCtcB45uqvl9Y5/BzK44L72Aqvavt4UPmCqb+w0UKzUJkzh0Tp1rThfHVwoQXXbOZvQ==", + "license": "MIT", + "dependencies": { + "flairup": "1.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16" + } + }, "node_modules/emoji-regex": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", @@ -7135,6 +7151,12 @@ "node": ">=0.10.0" } }, + "node_modules/flairup": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/flairup/-/flairup-1.0.0.tgz", + "integrity": "sha512-IKlE+pNvL2R+kVL1kEhUYqRxVqeFnjiIvHWDMLFXNaqyUdFXQM2wte44EfMYJNHkW16X991t2Zg8apKkhv7OBA==", + "license": "MIT" + }, "node_modules/flattie": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", diff --git a/package.json b/package.json index 8ec098b..5233554 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", + "emoji-picker-react": "^4.12.3", "framer-motion": "^12.18.1", "image-resize-compress": "^2.1.1", "js-cookie": "^3.0.5", diff --git a/src/components/CommentSystem/CommentSystem.jsx b/src/components/CommentSystem/CommentSystem.jsx index da112f1..6a0b118 100644 --- a/src/components/CommentSystem/CommentSystem.jsx +++ b/src/components/CommentSystem/CommentSystem.jsx @@ -1,10 +1,12 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useRef } from 'react'; +import EmojiPicker from 'emoji-picker-react'; import { Card } from '../ui/card'; import { Button } from '../ui/button'; import { Textarea } from '../ui/textarea'; import CommentThread from './CommentThread'; import { token, user_name, pb_id, siliconId, isLogin } from '../../lib/CookieValues'; import { useIsLoggedIn } from '../../lib/isLoggedIn'; + const CommentSystem = ({ topicId, pbId }) => { const isLoginCoockie = JSON.parse(isLogin); const { isLoggedIn, loading, error, sessionData } = useIsLoggedIn(); @@ -12,16 +14,55 @@ const CommentSystem = ({ topicId, pbId }) => { const [newComment, setNewComment] = useState(''); const [commentsLoading, setCommentsLoading] = useState(false); const [commentsError, setCommentsError] = useState(''); + const [showEmojiPicker, setShowEmojiPicker] = useState(false); + const textareaRef = useRef(null); + const emojiPickerRef = useRef(null); + + // 📌 Insert emoji at cursor position + const insertEmojiAtCursor = (emoji) => { + const textarea = textareaRef.current; + if (!textarea) return; + + const start = textarea.selectionStart; + const end = textarea.selectionEnd; + const text = newComment; + + const updatedText = text.slice(0, start) + emoji + text.slice(end); + setNewComment(updatedText); + + setTimeout(() => { + textarea.focus(); + textarea.setSelectionRange(start + emoji.length, start + emoji.length); + }, 0); + }; + + // 📌 Outside click to close emoji picker + useEffect(() => { + const handleClickOutside = (e) => { + if ( + emojiPickerRef.current && + !emojiPickerRef.current.contains(e.target) && + !e.target.closest('#emoji-toggle-btn') + ) { + setShowEmojiPicker(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, []); + + // 📌 Comment nesting logic const nestComments = (flatComments) => { const commentMap = {}; const rootComments = []; - + flatComments?.forEach(comment => { comment.replies = []; commentMap[comment.comment_id] = comment; }); - + flatComments?.forEach(comment => { if (comment.parent_comment_id?.Valid) { const parent = commentMap[comment.parent_comment_id.String]; @@ -30,59 +71,54 @@ const CommentSystem = ({ topicId, pbId }) => { rootComments.push(comment); } }); - - return rootComments.sort((a, b) => + + return rootComments.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); }; const fetchComments = async () => { try { - setCommentsLoading(true); - setCommentsError(''); - - const params = new URLSearchParams({ - topic_id: String(topicId), - }); - - // Only add silicon_id if it has a value - if (siliconId && siliconId !== 'null') { - params.append('silicon_id', siliconId); - } - - // Only add pb_id if it has a value - if (pb_id && pb_id !== 'null') { - params.append('pb_id', pb_id); - } - - const response = await fetch(`https://sp-comments-prod-pocndhvgmcnbacgb.siliconpin.com/comments?${params.toString()}`); - - if (!response.ok) { - const errorData = await response.json().catch(() => ({})); - throw new Error(errorData.message || `HTTP error! status: ${response.status}`); - } - - const flatComments = await response.json(); - setComments(nestComments(flatComments || [])); + setCommentsLoading(true); + setCommentsError(''); + + const params = new URLSearchParams({ topic_id: String(topicId) }); + + if (siliconId && siliconId !== 'null') { + params.append('silicon_id', siliconId); + } + + if (pb_id && pb_id !== 'null') { + params.append('pb_id', pb_id); + } + + const response = await fetch(`https://sp-comments-prod-pocndhvgmcnbacgb.siliconpin.com/comments?${params.toString()}`); + + if (!response.ok) { + const errorData = await response.json().catch(() => ({})); + throw new Error(errorData.message || `HTTP error! status: ${response.status}`); + } + + const flatComments = await response.json(); + setComments(nestComments(flatComments || [])); } catch (err) { - setCommentsError(err.message); - console.error('Fetch error:', err); + setCommentsError(err.message); } finally { - setCommentsLoading(false); + setCommentsLoading(false); } }; const postComment = async (text, parentId = null) => { try { setCommentsLoading(true); - + const payload = { topic_id: String(topicId), silicon_id: siliconId, - pb_id: pb_id, + pb_id: pbId, user_id: siliconId, user_name: user_name, comment_text: text, - is_approved: true + is_approved: true, }; if (parentId) { @@ -90,11 +126,11 @@ const CommentSystem = ({ topicId, pbId }) => { } const endpoint = parentId ? '/comments/reply' : '/comments'; - + const response = await fetch(`https://sp-comments-prod-pocndhvgmcnbacgb.siliconpin.com${endpoint}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload) + body: JSON.stringify(payload), }); if (!response.ok) { @@ -115,22 +151,22 @@ const CommentSystem = ({ topicId, pbId }) => { }, [topicId, siliconId, pbId]); return ( -
+

Comments

- + {commentsError && (
{commentsError}
)} - + {commentsLoading && comments.length === 0 ? (
Loading comments...
) : (
{comments.length > 0 ? ( comments.map(comment => ( - + )) ) : (

@@ -139,19 +175,19 @@ const CommentSystem = ({ topicId, pbId }) => { )}

)} -
- { - isLoginCoockie !== true ? ( -
-
-

To join the conversation, please log in first.

-
+ +
+ {isLoginCoockie !== true ? ( +
+
+

+ To join the conversation, please log in first. +

- ) : ( - '' - ) - } - +
+ ) : null} + +

Add a Comment

{ e.preventDefault(); @@ -159,9 +195,50 @@ const CommentSystem = ({ topicId, pbId }) => { postComment(newComment); setNewComment(''); }}> -