useCopyMarkdownFromUrl.ts50 lines · main
1'use client'
2
3import { useCallback, useState } from 'react'
4
5export type CopyMarkdownFromUrlOptions = {
6 /** When the markdown URL is missing or not OK, use this HTML string instead (e.g. rendered article). */
7 fallbackHtml?: () => string
8}
9
10const COPIED_FEEDBACK_MS = 2000
11
12/**
13 * Fetches markdown from `mdUrl`, falls back to optional HTML when the response is not OK,
14 * then writes the result to the clipboard.
15 */
16export async function copyMarkdownFromUrl(
17 mdUrl: string,
18 options?: CopyMarkdownFromUrlOptions
19): Promise<boolean> {
20 try {
21 const res = await fetch(mdUrl)
22 let text: string
23 if (res.ok) {
24 text = await res.text()
25 } else {
26 text = options?.fallbackHtml?.() ?? ''
27 if (!text) return false
28 }
29 await navigator.clipboard.writeText(text)
30 return true
31 } catch (error) {
32 console.error('Failed to copy markdown', error)
33 return false
34 }
35}
36
37export function useCopyMarkdownFromUrl() {
38 const [copied, setCopied] = useState(false)
39
40 const copyMarkdown = useCallback(async (mdUrl: string, options?: CopyMarkdownFromUrlOptions) => {
41 const ok = await copyMarkdownFromUrl(mdUrl, options)
42 if (ok) {
43 setCopied(true)
44 setTimeout(() => setCopied(false), COPIED_FEEDBACK_MS)
45 }
46 return ok
47 }, [])
48
49 return { copied, copyMarkdown }
50}