@@ -5,7 +5,7 @@ import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
55import { customTheme } from '../utils/customTheme' ;
66import PostMetadata from '../components/PostMetadata' ;
77import CodeModal from '../components/CodeModal' ;
8- import Toast from '../components/Toast ' ;
8+ import { useToast } from '../hooks/useToast ' ;
99import { AnimatePresence } from 'framer-motion' ;
1010import { ArrowLeftIcon , ArrowSquareOutIcon , ClipboardIcon , ArrowsOutSimpleIcon } from '@phosphor-icons/react' ;
1111
@@ -18,11 +18,33 @@ const LinkRenderer = ({ href, children }) => {
1818 ) ;
1919} ;
2020
21- const CodeBlock = ( { node, inline, className, children, openModal, showToast , ...props } ) => {
21+ const CodeBlock = ( { node, inline, className, children, openModal, ...props } ) => {
2222 const match = / l a n g u a g e - ( \w + ) / . exec ( className || '' ) ;
23+ const { addToast } = useToast ( ) ;
2324 const handleCopy = ( ) => {
24- navigator . clipboard . writeText ( String ( children ) ) ;
25- showToast ( 'Success' , 'Copied to clipboard!' ) ;
25+ const textToCopy = String ( children ) ;
26+ if ( navigator . clipboard && navigator . clipboard . writeText ) {
27+ navigator . clipboard . writeText ( textToCopy ) . then ( ( ) => {
28+ addToast ( { title : 'Success' , message : 'Copied to clipboard!' , duration : 3000 } ) ;
29+ } , ( ) => {
30+ addToast ( { title : 'Error' , message : 'Failed to copy!' , duration : 3000 } ) ;
31+ } ) ;
32+ } else {
33+ const textArea = document . createElement ( 'textarea' ) ;
34+ textArea . value = textToCopy ;
35+ textArea . style . position = 'fixed' ;
36+ textArea . style . left = '-9999px' ;
37+ document . body . appendChild ( textArea ) ;
38+ textArea . focus ( ) ;
39+ textArea . select ( ) ;
40+ try {
41+ document . execCommand ( 'copy' ) ;
42+ addToast ( { title : 'Success' , message : 'Copied to clipboard!' , duration : 3000 } ) ;
43+ } catch ( err ) {
44+ addToast ( { title : 'Error' , message : 'Failed to copy!' , duration : 3000 } ) ;
45+ }
46+ document . body . removeChild ( textArea ) ;
47+ }
2648 } ;
2749
2850 return ! inline && match ? (
@@ -61,7 +83,6 @@ const BlogPostPage = () => {
6183 const contentRef = useRef ( null ) ;
6284 const [ isModalOpen , setIsModalOpen ] = useState ( false ) ;
6385 const [ modalContent , setModalContent ] = useState ( '' ) ;
64- const [ toastMessage , setToastMessage ] = useState ( '' ) ;
6586
6687 const openModal = ( content ) => {
6788 setModalContent ( content ) ;
@@ -73,10 +94,6 @@ const BlogPostPage = () => {
7394 setModalContent ( '' ) ;
7495 } ;
7596
76- const showToast = ( title , message ) => {
77- setToastMessage ( { title, message } ) ;
78- } ;
79-
8097 useEffect ( ( ) => {
8198 const fetchPost = async ( ) => {
8299 setLoading ( true ) ;
@@ -177,7 +194,7 @@ const BlogPostPage = () => {
177194 < ArrowLeftIcon size = { 24 } /> Back to Home
178195 </ Link >
179196 < div ref = { contentRef } className = "prose prose-xl prose-dark max-w-none" >
180- < ReactMarkdown components = { { a : LinkRenderer , code : ( props ) => < CodeBlock { ...props } openModal = { openModal } showToast = { showToast } /> } } > { post . body } </ ReactMarkdown >
197+ < ReactMarkdown components = { { a : LinkRenderer , code : ( props ) => < CodeBlock { ...props } openModal = { openModal } /> } } > { post . body } </ ReactMarkdown >
181198 </ div >
182199 </ div >
183200 < div className = "hidden lg:block" >
@@ -188,11 +205,8 @@ const BlogPostPage = () => {
188205 < CodeModal isOpen = { isModalOpen } onClose = { closeModal } >
189206 { modalContent }
190207 </ CodeModal >
191- < AnimatePresence >
192- { toastMessage && < Toast title = { toastMessage . title } message = { toastMessage . message } duration = { 3000 } onClose = { ( ) => setToastMessage ( null ) } /> }
193- </ AnimatePresence >
194208 </ div >
195209 ) ;
196210} ;
197211
198- export default BlogPostPage ;
212+ export default BlogPostPage ;
0 commit comments