diff --git a/src/components/TopBar.astro b/src/components/TopBar.astro index 9fd9207..0ed1942 100644 --- a/src/components/TopBar.astro +++ b/src/components/TopBar.astro @@ -1,6 +1,5 @@ --- import LanguageSelector from './LanguageSelector.astro' -import GitHubAuth from './GitHubAuth.astro' import { t } from '../i18n/index.ts' interface Props { @@ -65,7 +64,6 @@ const { lang, currentPath, labels } = Astro.props > - diff --git a/src/components/discussion/Discussion.tsx b/src/components/discussion/Discussion.tsx index 77eae45..9ed7d45 100644 --- a/src/components/discussion/Discussion.tsx +++ b/src/components/discussion/Discussion.tsx @@ -1,232 +1,54 @@ -import React, { useState, useEffect } from 'react' -import type { Comment, DiscussionData } from './types' -import { t } from '../../i18n/index.ts' -import CommentItem from './CommentItem' +import React, { useEffect, useRef } from 'react' export interface DiscussionProps { - slug: string - labels: any + lang: string } -const REACTION_EMOJIS: Record = { - THUMBS_UP: 'πŸ‘', - THUMBS_DOWN: 'πŸ‘Ž', - LAUGH: 'πŸ˜„', - HOORAY: 'πŸŽ‰', - CONFUSED: 'πŸ˜•', - HEART: '❀️', - ROCKET: 'πŸš€', - EYES: 'πŸ‘€', -} +export default function Discussion({ lang }: DiscussionProps) { + const containerRef = useRef(null) -export default function Discussion({ slug, labels }: DiscussionProps) { - const [comments, setComments] = useState([]) - const [appData, setAppData] = useState(null) - const [newComment, setNewComment] = useState('') - const [loading, setLoading] = useState(true) - const [posting, setPosting] = useState(false) - const [loggedIn, setLoggedIn] = useState(false) + const getGiscusTheme = () => { + return document.documentElement.classList.contains('dark') ? 'dark_dimmed' : 'light_dimmed' + } useEffect(() => { - fetch('/api/auth/me') - .then(res => res.json()) - .then(data => { - setLoggedIn(!!data.user) - }) - .catch(() => setLoggedIn(false)) - - fetch(`/api/discussions/${slug}`) - .then(res => res.json()) - .then(data => { - if (data.discussion) { - setAppData(data.discussion) - setComments(data.discussion.comments.nodes) - } - }) - .finally(() => setLoading(false)) - }, [slug]) - - const submitComment = async () => { - if (!newComment.trim() || !appData) return - - setPosting(true) - try { - const res = await fetch('/api/discussions/comment', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ subjectId: appData.id, body: newComment }) - }) - const data = await res.json() - if (data.comment) { - setComments([...comments, data.comment]) - setNewComment('') + if (!containerRef.current) return + + const script = document.createElement('script') + script.src = 'https://giscus.app/client.js' + script.setAttribute('data-repo', '4byte-dev/4byte.dev') + script.setAttribute('data-repo-id', 'R_kgDORqu_NQ') + script.setAttribute('data-category', 'Makale YorumlarΔ±') + script.setAttribute('data-category-id', 'DIC_kwDORqu_Nc4C5G9p') + script.setAttribute('data-mapping', 'pathname') + script.setAttribute('data-strict', '0') + script.setAttribute('data-reactions-enabled', '1') + script.setAttribute('data-emit-metadata', '0') + script.setAttribute('data-input-position', 'bottom') + script.setAttribute('data-theme', getGiscusTheme()) + script.setAttribute('data-lang', lang === 'tr' ? 'tr' : 'en') + script.crossOrigin = 'anonymous' + script.async = true + + containerRef.current.appendChild(script) + + const observer = new MutationObserver(() => { + const iframe = document.querySelector('iframe.giscus-frame') as HTMLIFrameElement + if (iframe) { + iframe.contentWindow?.postMessage( + { giscus: { setConfig: { theme: getGiscusTheme() } } }, + 'https://giscus.app' + ) } - } catch (error) { - console.error('Failed to post comment', error) - } finally { - setPosting(false) - } - } - - const toggleUpvote = async () => { - if (!loggedIn || !appData) return - const action = appData.viewerHasUpvoted ? 'remove' : 'add' - - setAppData({ - ...appData, - viewerHasUpvoted: !appData.viewerHasUpvoted, - upvoteCount: appData.upvoteCount + (action === 'add' ? 1 : -1) }) + observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] }) - try { - await fetch('/api/discussions/upvote', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ subjectId: appData.id, action }) - }) - } catch (error) { } - } - - const toggleReaction = async (content: string, viewerHasReacted: boolean) => { - if (!loggedIn || !appData) return - const action = viewerHasReacted ? 'remove' : 'add' - - const newReactions = appData.reactionGroups?.map(r => { - if (r.content === content) { - return { - ...r, - viewerHasReacted: !viewerHasReacted, - users: { totalCount: r.users.totalCount + (viewerHasReacted ? -1 : 1) } - } - } - return r - }) || [] - - const didExist = newReactions.find(r => r.content === content) - if (!didExist && action === 'add') { - newReactions.push({ content, viewerHasReacted: true, users: { totalCount: 1 } }) - } - - setAppData({ ...appData, reactionGroups: newReactions }) - - try { - await fetch('/api/discussions/react', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ subjectId: appData.id, content, action }) - }) - } catch (error) { } - } - - const totalComments = comments.length + comments.reduce((acc, c) => acc + (c.replies?.nodes.length || 0), 0) - - if (loading) { - return
{t(labels, 'discussion.loading')}
- } + return () => observer.disconnect() + }, [lang]) return (
-
-

- {t(labels, 'discussion.title')} - - {totalComments} - -

- {!loggedIn && ( - - {t(labels, 'discussion.signIn')} - - )} -
- - {appData && ( -
- - -
- - {Object.keys(REACTION_EMOJIS).map(content => { - const reaction = appData.reactionGroups?.find(r => r.content === content) - const count = reaction?.users.totalCount || 0 - const userReacted = reaction?.viewerHasReacted || false - - if (count === 0 && !loggedIn) return null - - return ( - - ) - })} -
- )} - -
-
-
- -
-
-
-