22
33import { useState , useEffect , useRef } from 'react' ;
44import { motion , AnimatePresence } from 'framer-motion' ;
5- import { Check , Download , FileJson , Link2 , Loader2 , Share2 , Smartphone , X } from 'lucide-react' ;
5+ import {
6+ Check ,
7+ Code ,
8+ Download ,
9+ FileJson ,
10+ Link2 ,
11+ Loader2 ,
12+ Share2 ,
13+ Smartphone ,
14+ X ,
15+ } from 'lucide-react' ;
616import { toPng } from 'html-to-image' ;
717import type { DashboardExportData } from '@/types/dashboard' ;
818
@@ -117,6 +127,36 @@ export default function ShareSheet({ username, isOpen, onClose, exportData }: Sh
117127 setOptionState ( 'png' , 'error' ) ;
118128 }
119129 } ;
130+ const handleDownloadSVG = async ( ) => {
131+ setOptionState ( 'svg' , 'loading' ) ;
132+ try {
133+ const response = await fetch ( `/api/streak?user=${ encodeURIComponent ( username ) } ` ) ;
134+ if ( ! response . ok ) throw new Error ( 'Failed to fetch SVG' ) ;
135+ const svgText = await response . text ( ) ;
136+ const blob = new Blob ( [ svgText ] , { type : 'image/svg+xml' } ) ;
137+ const url = URL . createObjectURL ( blob ) ;
138+ const link = document . createElement ( 'a' ) ;
139+ link . download = `${ username } -commitpulse.svg` ;
140+ link . href = url ;
141+ link . click ( ) ;
142+ URL . revokeObjectURL ( url ) ;
143+ setOptionState ( 'svg' , 'success' ) ;
144+ } catch {
145+ setOptionState ( 'svg' , 'error' ) ;
146+ }
147+ } ;
148+
149+ const handleCopyMarkdown = async ( ) => {
150+ setOptionState ( 'markdown' , 'loading' ) ;
151+ try {
152+ const markdown = ` . replace ( username , `api/streak?user=${ username } ` ) } )` ;
153+ await navigator . clipboard . writeText ( markdown ) ;
154+ setOptionState ( 'markdown' , 'success' ) ;
155+ setTimeout ( ( ) => onClose ( ) , 800 ) ;
156+ } catch {
157+ setOptionState ( 'markdown' , 'error' ) ;
158+ }
159+ } ;
120160
121161 const handleDownloadJSON = ( ) => {
122162 setOptionState ( 'json' , 'loading' ) ;
@@ -200,6 +240,16 @@ export default function ShareSheet({ username, isOpen, onClose, exportData }: Sh
200240 glow : 'rgba(37,99,235,0.35)' ,
201241 action : handleLinkedIn ,
202242 } ,
243+
244+ {
245+ key : 'markdown' ,
246+ icon : Code ,
247+ label : 'Copy Markdown' ,
248+ description : 'Copy markdown snippet for your README' ,
249+ gradient : 'bg-zinc-800' ,
250+ glow : 'transparent' ,
251+ action : handleCopyMarkdown ,
252+ } ,
203253 {
204254 key : 'png' ,
205255 icon : Download ,
@@ -209,6 +259,15 @@ export default function ShareSheet({ username, isOpen, onClose, exportData }: Sh
209259 glow : 'transparent' ,
210260 action : handleDownloadPNG ,
211261 } ,
262+ {
263+ key : 'svg' ,
264+ icon : Download ,
265+ label : 'Download SVG' ,
266+ description : 'Download the raw monolith SVG' ,
267+ gradient : 'bg-zinc-800' ,
268+ glow : 'transparent' ,
269+ action : handleDownloadSVG ,
270+ } ,
212271 {
213272 key : 'json' ,
214273 icon : FileJson ,
@@ -315,7 +374,9 @@ export default function ShareSheet({ username, isOpen, onClose, exportData }: Sh
315374 ? 'Downloaded!'
316375 : opt . key === 'json'
317376 ? 'JSON Downloaded!'
318- : opt . label
377+ : opt . key === 'svg'
378+ ? 'SVG Downloaded!'
379+ : opt . label
319380 : state === 'error'
320381 ? 'Failed — try again'
321382 : opt . label }
0 commit comments