@@ -16,6 +16,7 @@ export default function DeepSeekProject() {
1616 const [ markdownContent , setMarkdownContent ] = useState < string > ( '' ) ;
1717 const [ heroData , setHeroData ] = useState < HeroData | null > ( null ) ;
1818 const [ isLoading , setIsLoading ] = useState ( true ) ;
19+ const [ copySuccess , setCopySuccess ] = useState ( false ) ;
1920
2021 useEffect ( ( ) => {
2122 const fetchMarkdownContent = async ( ) => {
@@ -98,6 +99,24 @@ export default function DeepSeekProject() {
9899 fetchMarkdownContent ( ) ;
99100 } , [ language ] ) ;
100101
102+ const handleCopyArticle = async ( ) => {
103+ try {
104+ // Get the raw markdown content without frontmatter
105+ const filename = language === 'zh' ? 'deepseek-sparse-attention-content-zh.md' : 'deepseek-sparse-attention-content.md' ;
106+ const response = await fetch ( `/content/deepseek-sparse-attention/${ filename } ` ) ;
107+ const content = await response . text ( ) ;
108+
109+ // Remove frontmatter if present
110+ const contentWithoutFrontmatter = content . replace ( / ^ - - - \n [ \s \S ] * ?\n - - - \n / , '' ) ;
111+
112+ await navigator . clipboard . writeText ( contentWithoutFrontmatter ) ;
113+ setCopySuccess ( true ) ;
114+ setTimeout ( ( ) => setCopySuccess ( false ) , 2000 ) ;
115+ } catch ( error ) {
116+ console . error ( 'Failed to copy article:' , error ) ;
117+ }
118+ } ;
119+
101120 if ( isLoading ) {
102121 return (
103122 < div className = "min-h-screen bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 flex items-center justify-center" >
@@ -184,8 +203,36 @@ export default function DeepSeekProject() {
184203 < article className = "max-w-4xl mx-auto" >
185204 { /* Content Card */ }
186205 < div className = "bg-white/5 backdrop-blur-xl border border-white/10 rounded-3xl shadow-2xl overflow-hidden" >
206+ { /* Copy Article Button */ }
207+ < div className = "px-8 sm:px-12 pt-8 pb-4" >
208+ < button
209+ onClick = { handleCopyArticle }
210+ className = { `group flex items-center gap-2 px-4 py-2 rounded-lg font-medium transition-all duration-300 ${
211+ copySuccess
212+ ? 'bg-green-500/20 text-green-400 border border-green-500/30'
213+ : 'bg-white/5 hover:bg-white/10 text-slate-300 hover:text-blue-400 border border-white/10 hover:border-blue-500/50'
214+ } `}
215+ >
216+ { copySuccess ? (
217+ < >
218+ < svg className = "w-4 h-4" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
219+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M5 13l4 4L19 7" />
220+ </ svg >
221+ { language === 'en' ? 'Copied!' : '已复制!' }
222+ </ >
223+ ) : (
224+ < >
225+ < svg className = "w-4 h-4 group-hover:scale-110 transition-transform" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
226+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
227+ </ svg >
228+ { language === 'en' ? 'Copy Article' : '复制文章' }
229+ </ >
230+ ) }
231+ </ button >
232+ </ div >
233+
187234 { /* Article Body */ }
188- < div className = "px-8 sm:px-12 py -12" >
235+ < div className = "px-8 sm:px-12 pb -12" >
189236 < div className = "prose prose-lg prose-invert max-w-none" >
190237 < MarkdownRenderer content = { markdownContent } />
191238 </ div >
0 commit comments