@@ -49,6 +49,7 @@ export default function HomePage() {
4949 const itemsPerPage = 20 ;
5050 const [ exportLoading , setExportLoading ] = useState ( false ) ;
5151 const [ exportError , setExportError ] = useState ( "" ) ;
52+ const [ shareUrl , setShareUrl ] = useState < string > ( "" ) ;
5253
5354 const allCommits = useMemo ( ( ) => {
5455 const commitMap = new Map < string , EnrichedCommit > ( ) ;
@@ -517,13 +518,16 @@ export default function HomePage() {
517518 }
518519 }
519520
520- async function handleExport ( ) {
521+ async function exportActivity ( shouldRedirect : boolean = true ) {
521522 if ( ! username || ( ! allCommits . length && ! issuesAndPRs . length ) ) {
522- return ;
523+ return null ;
523524 }
524525
525526 setExportLoading ( true ) ;
526527 setExportError ( "" ) ;
528+ if ( shouldRedirect ) {
529+ setShareUrl ( "" ) ;
530+ }
527531
528532 try {
529533 const now = new Date ( ) ;
@@ -575,14 +579,36 @@ export default function HomePage() {
575579 }
576580
577581 const data = await response . json ( ) ;
578- window . location . href = `/share/${ data . id } ` ;
582+ const newShareUrl = `${ window . location . origin } /share/${ data . id } ` ;
583+ setShareUrl ( newShareUrl ) ;
584+
585+ if ( shouldRedirect ) {
586+ window . location . href = newShareUrl ;
587+ }
588+
589+ return newShareUrl ;
579590 } catch ( err ) {
580591 setExportError ( err instanceof Error ? err . message : 'Failed to export activity' ) ;
592+ return null ;
581593 } finally {
582594 setExportLoading ( false ) ;
583595 }
584596 }
585597
598+ async function handleExport ( ) {
599+ exportActivity ( true ) ;
600+ }
601+
602+ async function handleTwitterShare ( ) {
603+ const url = await exportActivity ( false ) ;
604+ if ( url ) {
605+ window . open (
606+ `https://twitter.com/intent/tweet?text=${ encodeURIComponent ( `Check out my GitHub activity summary! ${ url } ` ) } ` ,
607+ '_blank'
608+ ) ;
609+ }
610+ }
611+
586612 const handleTypeToggle = ( type : 'commit' | 'issue' | 'pr' ) => {
587613 setSelectedTypes ( prev => {
588614 if ( prev . includes ( type ) ) {
@@ -684,6 +710,12 @@ export default function HomePage() {
684710 </ div >
685711 ) }
686712
713+ { exportError && (
714+ < div className = "mb-4 rounded-lg bg-red-500/20 p-4 text-red-200" >
715+ { exportError }
716+ </ div >
717+ ) }
718+
687719 { progress && (
688720 < div className = "mb-4 rounded-lg bg-blue-500/20 p-4 text-blue-200" >
689721 { progress . stage === 'checking-type' && (
@@ -747,35 +779,44 @@ export default function HomePage() {
747779 </ div >
748780 ) }
749781 { ! summaryLoading && (
750- < button
751- onClick = { handleExport }
752- disabled = { exportLoading }
753- className = "rounded-lg bg-blue-500/20 px-4 py-2 text-sm font-semibold text-blue-200 hover:bg-blue-500/30 disabled:opacity-50 flex items-center gap-2"
754- >
755- { exportLoading ? (
756- < >
757- < svg className = "animate-spin h-4 w-4" viewBox = "0 0 24 24" >
758- < circle className = "opacity-25" cx = "12" cy = "12" r = "10" stroke = "currentColor" strokeWidth = "4" fill = "none" />
759- < path className = "opacity-75" fill = "currentColor" d = "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
760- </ svg >
761- Share...
762- </ >
763- ) : (
764- < >
765- < svg className = "w-4 h-4" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
766- < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z" />
782+ < div className = "flex items-center gap-2" >
783+ < button
784+ onClick = { handleExport }
785+ disabled = { exportLoading }
786+ className = "rounded-lg bg-blue-500/20 px-4 py-2 text-sm font-semibold text-blue-200 hover:bg-blue-500/30 disabled:opacity-50 flex items-center gap-2"
787+ >
788+ { exportLoading ? (
789+ < >
790+ < svg className = "animate-spin h-4 w-4" viewBox = "0 0 24 24" >
791+ < circle className = "opacity-25" cx = "12" cy = "12" r = "10" stroke = "currentColor" strokeWidth = "4" fill = "none" />
792+ < path className = "opacity-75" fill = "currentColor" d = "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
793+ </ svg >
794+ Share...
795+ </ >
796+ ) : (
797+ < >
798+ < svg className = "w-4 h-4" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
799+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z" />
800+ </ svg >
801+ Share
802+ </ >
803+ ) }
804+ </ button >
805+ { summary && (
806+ < button
807+ onClick = { handleTwitterShare }
808+ disabled = { exportLoading }
809+ className = "rounded-lg bg-[#1DA1F2]/20 px-4 py-2 text-sm font-semibold text-[#1DA1F2] hover:bg-[#1DA1F2]/30 disabled:opacity-50 flex items-center gap-2"
810+ >
811+ < svg className = "w-4 h-4" fill = "currentColor" viewBox = "0 0 24 24" >
812+ < path d = "M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z" />
767813 </ svg >
768- Share
769- </ >
814+ Share on Twitter
815+ </ button >
770816 ) }
771- </ button >
817+ </ div >
772818 ) }
773819 </ div >
774- { exportError && (
775- < div className = "mt-2 text-red-400 text-sm" >
776- { exportError }
777- </ div >
778- ) }
779820 </ div >
780821
781822 { summaryError && (
0 commit comments