Skip to content

Commit d897191

Browse files
committed
feat: add placeholder for binary file
1 parent 0d952fa commit d897191

2 files changed

Lines changed: 102 additions & 0 deletions

File tree

app/pages/package-code/[[org]]/[packageName]/v/[version]/[...filePath].vue

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
PackageFileTreeResponse,
55
PackageFileContentResponse,
66
} from '#shared/types'
7+
import { isBinaryFilePath } from '~/utils/file-types'
78
89
definePageMeta({
910
name: 'code',
@@ -105,6 +106,14 @@ const isViewingFile = computed(() => currentNode.value?.type === 'file')
105106
106107
// Maximum file size we'll try to load (500KB) - must match server
107108
const MAX_FILE_SIZE = 500 * 1024
109+
110+
const isBinaryFile = computed(() => !!filePath.value && isBinaryFilePath(filePath.value))
111+
const showBinaryContent = shallowRef(false)
112+
113+
watch(filePath, () => {
114+
showBinaryContent.value = false
115+
})
116+
108117
const isFileTooLarge = computed(() => {
109118
const size = currentNode.value?.size
110119
return size !== undefined && size > MAX_FILE_SIZE
@@ -116,6 +125,10 @@ const fileContentUrl = computed(() => {
116125
if (!filePath.value || !fileTree.value || isFileTooLarge.value || !isViewingFile.value) {
117126
return null
118127
}
128+
// Don't fetch binary files until user explicitly requests rendering
129+
if (isBinaryFile.value && !showBinaryContent.value) {
130+
return null
131+
}
119132
return `/api/registry/file/${packageName.value}/v/${version.value}/${filePath.value}`
120133
})
121134
@@ -519,6 +532,25 @@ defineOgImageComponent('Default', {
519532
/>
520533
</template>
521534

535+
<!-- Binary file placeholder -->
536+
<div
537+
v-else-if="isViewingFile && isBinaryFile && !showBinaryContent"
538+
class="py-20 text-center"
539+
>
540+
<div class="i-lucide:binary w-12 h-12 mx-auto text-fg-subtle mb-4" />
541+
<p class="text-fg-muted mb-2">Binary file</p>
542+
<p class="text-fg-subtle text-sm mb-4">Rendering may produce garbled output.</p>
543+
<div class="flex items-center justify-center gap-3">
544+
<ButtonBase @click="showBinaryContent = true"> Render anyway </ButtonBase>
545+
<LinkBase
546+
variant="button-secondary"
547+
:to="`https://cdn.jsdelivr.net/npm/${packageName}@${version}/${filePath}`"
548+
>
549+
View raw file
550+
</LinkBase>
551+
</div>
552+
</div>
553+
522554
<!-- File too large warning -->
523555
<div v-else-if="isViewingFile && isFileTooLarge" class="py-20 text-center">
524556
<div class="i-lucide:file-text w-12 h-12 mx-auto text-fg-subtle mb-4" />

app/utils/file-types.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Extensions that are binary and cannot be meaningfully displayed as text
2+
const BINARY_EXTENSIONS = new Set([
3+
// Images
4+
'png',
5+
'jpg',
6+
'jpeg',
7+
'gif',
8+
'webp',
9+
'ico',
10+
'bmp',
11+
'tiff',
12+
'tif',
13+
'avif',
14+
'heic',
15+
'heif',
16+
// Fonts
17+
'woff',
18+
'woff2',
19+
'ttf',
20+
'otf',
21+
'eot',
22+
// Archives
23+
'zip',
24+
'tar',
25+
'gz',
26+
'tgz',
27+
'bz2',
28+
'xz',
29+
'7z',
30+
'rar',
31+
// Executables / compiled
32+
'exe',
33+
'dll',
34+
'so',
35+
'dylib',
36+
'node',
37+
'wasm',
38+
'pyc',
39+
'class',
40+
// Media
41+
'mp3',
42+
'mp4',
43+
'ogg',
44+
'wav',
45+
'avi',
46+
'mov',
47+
'webm',
48+
'flac',
49+
'aac',
50+
'mkv',
51+
// Documents
52+
'pdf',
53+
'doc',
54+
'docx',
55+
'xls',
56+
'xlsx',
57+
'ppt',
58+
'pptx',
59+
// Data
60+
'bin',
61+
'dat',
62+
'db',
63+
'sqlite',
64+
'sqlite3',
65+
])
66+
67+
export function isBinaryFilePath(filePath: string): boolean {
68+
const ext = filePath.split('.').pop()?.toLowerCase() ?? ''
69+
return BINARY_EXTENSIONS.has(ext)
70+
}

0 commit comments

Comments
 (0)