11import { useClipboard } from '@vueuse/core'
22import { join } from 'pathe'
33import { useData } from 'vitepress'
4- import { computed } from 'vue'
4+ import { computed , ref } from 'vue'
55import { toast } from 'vue-sonner'
66import { useChangelog } from './useChangelog'
77
88export function useSourceCode ( ) {
99 const { page, frontmatter } = useData ( )
1010 const { repoURL } = useChangelog ( )
11- const { copy, copied, isSupported } = useClipboard ( )
11+
12+ // Use a safer approach for SSR compatibility
13+ const clipboardResult = typeof window !== 'undefined'
14+ ? useClipboard ( )
15+ : { copy : async ( ) => { } , copied : ref ( false ) , isSupported : ref ( false ) }
16+ const { copy, copied, isSupported } = clipboardResult
1217
1318 const showSourceCode = computed ( ( ) => {
1419 if ( ! isSupported . value )
@@ -97,14 +102,65 @@ export function useSourceCode() {
97102 . replace ( '/blob/' , '/' )
98103 }
99104
100- const response = await fetch ( rawUrl )
101- if ( ! response . ok ) {
102- throw new Error ( `HTTP ${ response . status } : ${ response . statusText } ` )
105+ // Generate multiple URL variations to try
106+ const urlsToTry : string [ ] = [ ]
107+ const filePath = page . value . filePath
108+
109+ if ( repoURL . value ) {
110+ const baseRawUrl = repoURL . value
111+ . replace ( 'github.com' , 'raw.githubusercontent.com' )
112+ . replace ( / \/ $ / , '' )
113+
114+ // Try different path combinations
115+ const pathVariations = [
116+ getRepoFilePath . value , // Current computed path
117+ filePath , // Original file path without modifications
118+ filePath . startsWith ( '/' ) ? filePath . slice ( 1 ) : filePath , // Remove leading slash
119+ ]
120+
121+ // If current path has docs/, also try without it
122+ if ( getRepoFilePath . value . includes ( 'docs/' ) ) {
123+ pathVariations . push ( getRepoFilePath . value . replace ( 'docs/' , '' ) )
124+ }
125+
126+ // If current path doesn't have docs/, also try with it
127+ if ( ! getRepoFilePath . value . includes ( 'docs/' ) ) {
128+ pathVariations . push ( join ( 'docs' , getRepoFilePath . value ) )
129+ }
130+
131+ // Generate full URLs for each path variation
132+ pathVariations . forEach ( ( path ) => {
133+ const cleanPath = path . startsWith ( '/' ) ? path . slice ( 1 ) : path
134+ urlsToTry . push ( `${ baseRawUrl } /main/${ cleanPath } ` )
135+ } )
136+ }
137+ else {
138+ // Fallback to original logic if no repoURL
139+ urlsToTry . push ( rawUrl )
140+ }
141+
142+ // Remove duplicates
143+ const uniqueUrls = [ ...new Set ( urlsToTry ) ]
144+
145+ let lastError : Error | null = null
146+
147+ for ( const url of uniqueUrls ) {
148+ try {
149+ const response = await fetch ( url )
150+ if ( response . ok ) {
151+ const content = await response . text ( )
152+ await copy ( content )
153+ toast . success ( 'Page content copied to clipboard' )
154+ return
155+ }
156+ lastError = new Error ( `HTTP ${ response . status } : ${ response . statusText } ` )
157+ }
158+ catch ( error ) {
159+ lastError = error as Error
160+ }
103161 }
104162
105- const content = await response . text ( )
106- await copy ( content )
107- toast . success ( 'Page content copied to clipboard' )
163+ throw lastError || new Error ( 'All URL attempts failed' )
108164 }
109165 catch ( error ) {
110166 console . error ( 'Failed to copy markdown content:' , error )
@@ -115,8 +171,13 @@ export function useSourceCode() {
115171
116172 const copyMarkdownLink = async ( ) => {
117173 try {
174+ if ( typeof window === 'undefined' ) {
175+ toast . error ( 'Copy functionality not available during server-side rendering' )
176+ return
177+ }
178+
118179 const pageTitle = page . value . title || document . title || 'Documentation Page'
119- const currentURL = typeof window !== 'undefined' ? window . location . href : ''
180+ const currentURL = window . location . href
120181 const markdownLink = `[${ pageTitle } ](${ currentURL } )`
121182
122183 await copy ( markdownLink )
0 commit comments