mirror of
				https://github.com/r-freeman/portfolio.git
				synced 2025-11-03 23:31:11 +00:00 
			
		
		
		
	Add copy button to pre components
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Build And Publish / BuildAndPublish (push) Successful in 3m11s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Build And Publish / BuildAndPublish (push) Successful in 3m11s
				
			This commit is contained in:
		
							parent
							
								
									191705bf8b
								
							
						
					
					
						commit
						c3b3a0d845
					
				
							
								
								
									
										10
									
								
								components/icons/CheckIcon.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								components/icons/CheckIcon.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					import {Props} from '@/types'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function CheckIcon(props: Props) {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <svg fill="none" strokeWidth={1.5} stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"
 | 
				
			||||||
 | 
					             aria-hidden="true" {...props}>
 | 
				
			||||||
 | 
					            <path strokeLinecap="round" strokeLinejoin="round" d="m4.5 12.75 6 6 9-13.5"/>
 | 
				
			||||||
 | 
					        </svg>
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								components/icons/CopyIcon.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								components/icons/CopyIcon.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					import {Props} from '@/types'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function CopyIcon(props: Props) {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <svg fill="none" strokeWidth={1.5} stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"
 | 
				
			||||||
 | 
					             aria-hidden="true" {...props}>
 | 
				
			||||||
 | 
					            <path strokeLinecap="round" strokeLinejoin="round"
 | 
				
			||||||
 | 
					                  d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 0 1-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 0 1 1.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 0 0-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 0 1-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H9.75"/>
 | 
				
			||||||
 | 
					        </svg>
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -5,13 +5,11 @@ import {Prose} from '@/components/ui/Prose'
 | 
				
			|||||||
import {Views} from '@/components/ui/Views'
 | 
					import {Views} from '@/components/ui/Views'
 | 
				
			||||||
import {ArrowDownIcon} from '@/components/icons/ArrowDownIcon'
 | 
					import {ArrowDownIcon} from '@/components/icons/ArrowDownIcon'
 | 
				
			||||||
import ArticleNav from '@/components/ui/ArticleNav'
 | 
					import ArticleNav from '@/components/ui/ArticleNav'
 | 
				
			||||||
import Comments from '@/components/ui/Comments'
 | 
					import {Comments} from '@/components/ui/Comments'
 | 
				
			||||||
import {getAllArticles} from '@/lib/getAllArticles'
 | 
					import {getAllArticles} from '@/lib/getAllArticles'
 | 
				
			||||||
import {getComments} from '@/lib/getComments'
 | 
					import {getComments} from '@/lib/getComments'
 | 
				
			||||||
import {format} from 'date-fns'
 | 
					import {format} from 'date-fns'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import type {Comment} from '@/types'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type ArticleLayout = {
 | 
					type ArticleLayout = {
 | 
				
			||||||
    title: string
 | 
					    title: string
 | 
				
			||||||
    date: string
 | 
					    date: string
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										29
									
								
								components/ui/Code.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								components/ui/Code.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					'use client'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import React, {ReactNode, useRef, useState} from 'react'
 | 
				
			||||||
 | 
					import {CopyIcon} from '@/components/icons/CopyIcon'
 | 
				
			||||||
 | 
					import {CheckIcon} from '@/components/icons/CheckIcon'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function Code({children}: { children: ReactNode }) {
 | 
				
			||||||
 | 
					    const [copied, setCopied] = useState<boolean>(false)
 | 
				
			||||||
 | 
					    const preRef = useRef<HTMLPreElement>(null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const handleCopy = async (e: React.MouseEvent<HTMLButtonElement>) => {
 | 
				
			||||||
 | 
					        e.preventDefault()
 | 
				
			||||||
 | 
					        await navigator.clipboard.writeText(preRef.current?.innerText ?? '')
 | 
				
			||||||
 | 
					        setCopied(true)
 | 
				
			||||||
 | 
					        setTimeout(() => setCopied(false), 1000)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <pre className="relative" ref={preRef}>
 | 
				
			||||||
 | 
					                <button className="absolute top-0 right-0 m-5" onClick={handleCopy} aria-label="Copy code">
 | 
				
			||||||
 | 
					                {copied ? <CheckIcon className="size-6 text-indigo-500"/> :
 | 
				
			||||||
 | 
					                    <CopyIcon className="size-6 text-zinc-400 hover:text-zinc-50"/>}
 | 
				
			||||||
 | 
					                </button>
 | 
				
			||||||
 | 
					            <div className="mt-5 sm:mt-0 pb-5 overflow-auto ">
 | 
				
			||||||
 | 
					            {children}
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </pre>
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -205,7 +205,7 @@ type CommentsProps = {
 | 
				
			|||||||
    comments?: any
 | 
					    comments?: any
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function Comments({slug, comments}: CommentsProps) {
 | 
					export function Comments({slug, comments}: CommentsProps) {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <CommentFormProvider>
 | 
					        <CommentFormProvider>
 | 
				
			||||||
            <ReplyProvider>
 | 
					            <ReplyProvider>
 | 
				
			||||||
 | 
				
			|||||||
@ -45,12 +45,7 @@ export const getCurrentlyPlaying = async () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getRecentlyPlayed = async () => {
 | 
					export const getRecentlyPlayed = async () => {
 | 
				
			||||||
    try {
 | 
					    const {access_token}: Response = await getAccessToken() as Response
 | 
				
			||||||
        const {access_token}: Response = await getAccessToken() as Response
 | 
					 | 
				
			||||||
    } catch(e) {
 | 
					 | 
				
			||||||
        console.error(e)
 | 
					 | 
				
			||||||
        return null
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return await fetch(SPOTIFY_RECENTLY_PLAYED, {
 | 
					    return await fetch(SPOTIFY_RECENTLY_PLAYED, {
 | 
				
			||||||
        headers: {
 | 
					        headers: {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,6 @@
 | 
				
			|||||||
import type {MDXComponents} from 'mdx/types'
 | 
					import type {MDXComponents} from 'mdx/types'
 | 
				
			||||||
 | 
					import React from 'react'
 | 
				
			||||||
 | 
					import {Code} from '@/components/ui/Code'
 | 
				
			||||||
import {Heading} from './components/ui/Heading'
 | 
					import {Heading} from './components/ui/Heading'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This file allows you to provide custom React components
 | 
					// This file allows you to provide custom React components
 | 
				
			||||||
@ -11,6 +13,7 @@ export function useMDXComponents(components: MDXComponents): MDXComponents {
 | 
				
			|||||||
    return {
 | 
					    return {
 | 
				
			||||||
        h2: ({children}) => <Heading as="h2">{children}</Heading>,
 | 
					        h2: ({children}) => <Heading as="h2">{children}</Heading>,
 | 
				
			||||||
        h3: ({children}) => <Heading as="h3">{children}</Heading>,
 | 
					        h3: ({children}) => <Heading as="h3">{children}</Heading>,
 | 
				
			||||||
 | 
					        pre: ({children}) => <Code>{children}</Code>,
 | 
				
			||||||
        // Allows customizing built-in components, e.g. to add styling.
 | 
					        // Allows customizing built-in components, e.g. to add styling.
 | 
				
			||||||
        // h1: ({ children }) => <h1 style={{ fontSize: "100px" }}>{children}</h1>,
 | 
					        // h1: ({ children }) => <h1 style={{ fontSize: "100px" }}>{children}</h1>,
 | 
				
			||||||
        ...components
 | 
					        ...components
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user