11import DashboardFileType from '@/components/file/DashboardFileType' ;
2+ import TagPill from '@/components/pages/files/tags/TagPill' ;
23import { isCode } from '@/lib/code' ;
34import { config as zConfig } from '@/lib/config' ;
45import { verifyPassword } from '@/lib/crypto' ;
@@ -13,6 +14,7 @@ import { readThemes } from '@/lib/theme/file';
1314import { formatRootUrl } from '@/lib/url' ;
1415import {
1516 ActionIcon ,
17+ Anchor ,
1618 Box ,
1719 Button ,
1820 Center ,
@@ -22,9 +24,10 @@ import {
2224 Paper ,
2325 PasswordInput ,
2426 Text ,
27+ Tooltip ,
2528 TypographyStylesProvider ,
2629} from '@mantine/core' ;
27- import { IconDownload , IconInfoCircleFilled } from '@tabler/icons-react' ;
30+ import { IconDownload , IconExternalLink , IconInfoCircleFilled } from '@tabler/icons-react' ;
2831import { sanitize } from 'isomorphic-dompurify' ;
2932import { GetServerSideProps , InferGetServerSidePropsType } from 'next' ;
3033import Head from 'next/head' ;
@@ -76,32 +79,47 @@ export default function ViewFileId({
7679 < meta
7780 property = 'og:title'
7881 content = {
79- parseString ( user . view . embedTitle , { file : file as File , user : user as User , ...metrics } ) ?? ''
82+ parseString ( user . view . embedTitle , {
83+ file : file as unknown as File ,
84+ user : user as User ,
85+ ...metrics ,
86+ } ) ?? ''
8087 }
8188 />
8289 ) }
8390 { user ?. view ! . embedDescription && user ?. view . embed && (
8491 < meta
8592 property = 'og:description'
8693 content = {
87- parseString ( user . view . embedDescription , { file : file as File , user : user as User , ...metrics } ) ??
88- ''
94+ parseString ( user . view . embedDescription , {
95+ file : file as unknown as File ,
96+ user : user as User ,
97+ ...metrics ,
98+ } ) ?? ''
8999 }
90100 />
91101 ) }
92102 { user ?. view ! . embedSiteName && user ?. view . embed && (
93103 < meta
94104 property = 'og:site_name'
95105 content = {
96- parseString ( user . view . embedSiteName , { file : file as File , user : user as User , ...metrics } ) ?? ''
106+ parseString ( user . view . embedSiteName , {
107+ file : file as unknown as File ,
108+ user : user as User ,
109+ ...metrics ,
110+ } ) ?? ''
97111 }
98112 />
99113 ) }
100114 { user ?. view ! . embedColor && user ?. view . embed && (
101115 < meta
102116 property = 'theme-color'
103117 content = {
104- parseString ( user . view . embedColor , { file : file as File , user : user as User , ...metrics } ) ?? ''
118+ parseString ( user . view . embedColor , {
119+ file : file as unknown as File ,
120+ user : user as User ,
121+ ...metrics ,
122+ } ) ?? ''
105123 }
106124 />
107125 ) }
@@ -212,7 +230,7 @@ export default function ViewFileId({
212230 dangerouslySetInnerHTML = { {
213231 __html : sanitize (
214232 parseString ( user . view . content , {
215- file : file as File ,
233+ file : file as unknown as File ,
216234 link : {
217235 returned : `${ host } ${ formatRootUrl ( filesRoute ?? '/u' , file . name ! ) } ` ,
218236 raw : `${ host } /raw/${ file . name } ` ,
@@ -233,49 +251,74 @@ export default function ViewFileId({
233251
234252 { file . name ! . endsWith ( '.md' ) || file . name ! . endsWith ( '.tex' ) ? (
235253 < Paper m = 'md' p = 'md' withBorder >
236- < DashboardFileType file = { file as File } password = { pw } show code = { code } />
254+ < DashboardFileType file = { file as unknown as File } password = { pw } show code = { code } />
237255 </ Paper >
238256 ) : (
239257 < Box m = 'sm' >
240- < DashboardFileType file = { file as File } password = { pw } show code = { code } />
258+ < DashboardFileType file = { file as unknown as File } password = { pw } show code = { code } />
241259 </ Box >
242260 ) }
243261 </ >
244262 ) : (
245263 < >
246264 { meta }
247265 < Center h = '100%' >
248- < Paper
249- m = 'md'
250- p = 'md'
251- shadow = 'md'
252- radius = 'md'
253- withBorder
254- >
266+ < Paper m = 'md' p = 'md' shadow = 'md' radius = 'md' withBorder >
255267 < Group justify = 'space-between' mb = 'sm' >
256268 < Group >
257269 < Text size = 'lg' fw = { 700 } display = 'flex' >
258- { file . name }
270+ { file . name } { ' ' }
259271 </ Text >
272+ { user ?. view ! . showTags && (
273+ < Group gap = { 4 } > { file . tags ?. map ( ( tag ) => < TagPill key = { tag . id } tag = { tag } /> ) } </ Group >
274+ ) }
275+ { user ?. view ! . showFolder &&
276+ file . Folder &&
277+ ( file . Folder . public ? (
278+ < Tooltip label = 'View folder' >
279+ < Anchor component = { Link } ml = 'sm' href = { `/folder/${ file . Folder . id } ` } >
280+ { file . Folder . name }
281+ </ Anchor >
282+ </ Tooltip >
283+ ) : (
284+ < Text ml = 'sm' size = 'sm' c = 'dimmed' >
285+ { file . Folder . name }
286+ </ Text >
287+ ) ) }
260288 { user ?. view ! . showMimetype && (
261289 < Text size = 'sm' c = 'dimmed' ml = 'sm' style = { { alignSelf : 'center' } } >
262290 { file . type }
263291 </ Text >
264292 ) }
265293 </ Group >
266294
267- < ActionIcon
268- size = 'md'
269- variant = 'outline'
270- component = { Link }
271- href = { `/raw/${ file . name } ?download=true${ pw ? `&pw=${ pw } ` : '' } ` }
272- target = '_blank'
273- >
274- < IconDownload size = '1rem' />
275- </ ActionIcon >
295+ < ActionIcon . Group >
296+ < Tooltip label = 'View raw file' >
297+ < ActionIcon
298+ size = 'md'
299+ variant = 'outline'
300+ component = { Link }
301+ href = { `/raw/${ file . name } ${ pw ? `?pw=${ pw } ` : '' } ` }
302+ target = '_blank'
303+ >
304+ < IconExternalLink size = '1rem' />
305+ </ ActionIcon >
306+ </ Tooltip >
307+ < Tooltip label = 'Download file' >
308+ < ActionIcon
309+ size = 'md'
310+ variant = 'outline'
311+ component = { Link }
312+ href = { `/raw/${ file . name } ?download=true${ pw ? `&pw=${ pw } ` : '' } ` }
313+ target = '_blank'
314+ >
315+ < IconDownload size = '1rem' />
316+ </ ActionIcon >
317+ </ Tooltip >
318+ </ ActionIcon . Group >
276319 </ Group >
277320
278- < DashboardFileType allowZoom file = { file as File } password = { pw } show />
321+ < DashboardFileType allowZoom file = { file as unknown as File } password = { pw } show />
279322
280323 { mounted && user ?. view ! . content && (
281324 < TypographyStylesProvider >
@@ -285,7 +328,7 @@ export default function ViewFileId({
285328 dangerouslySetInnerHTML = { {
286329 __html : sanitize (
287330 parseString ( user ?. view . content , {
288- file : file as File ,
331+ file : file as unknown as File ,
289332 link : {
290333 returned : `${ host } ${ formatRootUrl ( filesRoute ?? '/u' , file . name ! ) } ` ,
291334 raw : `${ host } /raw/${ file . name } ` ,
@@ -308,8 +351,40 @@ export default function ViewFileId({
308351 ) ;
309352}
310353
354+ const getFile = async ( id : string ) =>
355+ prisma . file . findFirst ( {
356+ where : {
357+ name : id as string ,
358+ } ,
359+ select : {
360+ ...fileSelect ,
361+ password : true ,
362+ userId : true ,
363+ thumbnail : {
364+ select : {
365+ path : true ,
366+ } ,
367+ } ,
368+ tags : {
369+ select : {
370+ id : true ,
371+ name : true ,
372+ color : true ,
373+ } ,
374+ } ,
375+
376+ Folder : {
377+ select : {
378+ id : true ,
379+ public : true ,
380+ name : true ,
381+ } ,
382+ } ,
383+ } ,
384+ } ) ;
385+
311386export const getServerSideProps : GetServerSideProps < {
312- file : Partial < File > ;
387+ file : Partial < NonNullable < Awaited < ReturnType < typeof getFile > > > > ;
313388 password ?: boolean ;
314389 pw ?: string ;
315390 code : boolean ;
@@ -325,22 +400,7 @@ export const getServerSideProps: GetServerSideProps<{
325400 const { config : libConfig , reloadSettings } = await import ( '@/lib/config' ) ;
326401 if ( ! libConfig ) await reloadSettings ( ) ;
327402
328- const file = await prisma . file . findFirst ( {
329- where : {
330- name : id as string ,
331- } ,
332- select : {
333- ...fileSelect ,
334- password : true ,
335- userId : true ,
336- tags : false ,
337- thumbnail : {
338- select : {
339- path : true ,
340- } ,
341- } ,
342- } ,
343- } ) ;
403+ const file = await getFile ( id as string ) ;
344404 if ( ! file || ! file . userId ) return { notFound : true } ;
345405
346406 if ( file . maxViews && file . views >= file . maxViews ) return { notFound : true } ;
0 commit comments