useCopyMarkdownFromUrl.ts 1.3 KB

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