Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 41b7352

Browse files
Add button to download file
1 parent 17de083 commit 41b7352

File tree

13 files changed

+116
-48
lines changed

13 files changed

+116
-48
lines changed

‎packages/gitbook/src/components/DocumentView/File.tsx‎

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,85 @@
11
import { type DocumentBlockFile, SiteInsightsLinkPosition } from '@gitbook/api';
22

3+
import { t } from '@/intl/translate';
34
import { getSimplifiedContentType } from '@/lib/files';
45
import { resolveContentRef } from '@/lib/references';
5-
import { tcls } from '@/lib/tailwind';
66

7-
import { Link } from '../primitives';
7+
import { getSpaceLanguage } from '@/intl/server';
8+
import { Button, Link } from '../primitives';
9+
import { DownloadButton } from '../primitives/DownloadButton';
810
import type { BlockProps } from './Block';
911
import { Caption } from './Caption';
1012
import { FileIcon } from './FileIcon';
1113

1214
export async function File(props: BlockProps<DocumentBlockFile>) {
1315
const { block, context } = props;
1416

15-
const contentRef = context.contentContext
16-
? await resolveContentRef(block.data.ref, context.contentContext)
17-
: null;
17+
if (!context.contentContext) {
18+
return null;
19+
}
20+
21+
const contentRef = await resolveContentRef(block.data.ref, context.contentContext);
1822
const file = contentRef?.file;
1923

2024
if (!file) {
2125
return null;
2226
}
2327

28+
const language = getSpaceLanguage(context.contentContext);
2429
const contentType = getSimplifiedContentType(file.contentType);
30+
const insights = {
31+
type: 'link_click' as const,
32+
link: {
33+
target: block.data.ref,
34+
position: SiteInsightsLinkPosition.Content,
35+
},
36+
};
2537

2638
return (
2739
<Caption {...props} withBorder>
28-
<Link
29-
href={file.downloadURL}
30-
download={file.name}
31-
insights={{
32-
type: 'link_click',
33-
link: {
34-
target: block.data.ref,
35-
position: SiteInsightsLinkPosition.Content,
36-
},
37-
}}
38-
className={tcls('group/file', 'flex', 'flex-row', 'items-center', 'px-5', 'py-3')}
39-
>
40-
<div
41-
className={tcls(
42-
'min-w-14',
43-
'mr-5',
44-
'pr-5',
45-
'flex',
46-
'flex-col',
47-
'items-center',
48-
'gap-1',
49-
'border-r',
50-
'border-tint-subtle'
51-
)}
52-
>
40+
<div className="flex items-center px-5 py-3">
41+
<div className="mr-5 flex min-w-14 flex-col items-center gap-1 border-tint-subtle border-r pr-5">
5342
<div>
54-
<FileIcon
55-
contentType={contentType}
56-
className={tcls('size-5', 'text-primary')}
57-
/>
58-
</div>
59-
<div
60-
className={tcls(
61-
'text-xs',
62-
'text-tint',
63-
'group-hover/file:text-tint-strong'
64-
)}
65-
>
66-
{getHumanFileSize(file.size)}
43+
<FileIcon contentType={contentType} className="size-5 text-primary" />
6744
</div>
45+
<div className="text-hint text-xs">{getHumanFileSize(file.size)}</div>
6846
</div>
69-
<div>
70-
<div className={tcls('text-base')}>{file.name}</div>
71-
<div className={tcls('text-sm', 'opacity-9', 'dark:opacity-8')}>
72-
{contentType}
47+
<div className="flex-1">
48+
<div className="text-base">
49+
<Link
50+
href={file.downloadURL}
51+
target="_blank"
52+
insights={insights}
53+
className="hover:underline"
54+
>
55+
{file.name}
56+
</Link>
7357
</div>
58+
<div className="text-sm opacity-9 dark:opacity-8">{contentType}</div>
59+
</div>
60+
<div className="flex shrink-0 gap-2">
61+
<DownloadButton
62+
icon="download"
63+
size="xsmall"
64+
variant="secondary"
65+
downloadUrl={file.downloadURL}
66+
filename={file.name}
67+
insights={insights}
68+
>
69+
{t(language, 'download')}
70+
</DownloadButton>
71+
<Button
72+
icon="arrow-up-right-from-square"
73+
size="xsmall"
74+
variant="secondary"
75+
href={file.downloadURL}
76+
target="_blank"
77+
insights={insights}
78+
>
79+
{t(language, 'open')}
80+
</Button>
7481
</div>
75-
</Link>
82+
</div>
7683
</Caption>
7784
);
7885
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use client';
2+
import { Button, type ButtonProps } from './Button';
3+
4+
/**
5+
* Button that triggers a file download when clicked.
6+
*/
7+
export function DownloadButton(
8+
props: Omit<ButtonProps, 'onClick' | 'href'> & { downloadUrl: string; filename: string }
9+
) {
10+
const { downloadUrl, filename, ...buttonProps } = props;
11+
12+
return (
13+
<Button
14+
{...buttonProps}
15+
onClick={(e) => {
16+
e.preventDefault();
17+
void forceDownload(downloadUrl, filename);
18+
}}
19+
/>
20+
);
21+
}
22+
23+
/**
24+
* Force download a file from a given URL with a specified filename.
25+
*/
26+
async function forceDownload(url: string, filename: string) {
27+
const response = await fetch(url);
28+
const blob = await response.blob();
29+
const objectUrl = URL.createObjectURL(blob);
30+
31+
const link = document.createElement('a');
32+
link.href = objectUrl;
33+
link.download = filename;
34+
document.body.appendChild(link);
35+
link.click();
36+
document.body.removeChild(link);
37+
38+
URL.revokeObjectURL(objectUrl);
39+
}

‎packages/gitbook/src/intl/translations/de.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,6 @@ export const de = {
130130
hint_warning: 'Warnung',
131131
hint_danger: 'Gefahr',
132132
hint_success: 'Erfolg',
133+
download: 'Herunterladen',
134+
open: 'Öffnen',
133135
};

‎packages/gitbook/src/intl/translations/en.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,6 @@ export const en = {
127127
hint_warning: 'Warning',
128128
hint_danger: 'Danger',
129129
hint_success: 'Success',
130+
download: 'Download',
131+
open: 'Open',
130132
};

‎packages/gitbook/src/intl/translations/es.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,6 @@ export const es: TranslationLanguage = {
131131
hint_warning: 'Advertencia',
132132
hint_danger: 'Peligro',
133133
hint_success: 'Éxito',
134+
download: 'Descargar',
135+
open: 'Abrir',
134136
};

‎packages/gitbook/src/intl/translations/fr.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,6 @@ export const fr = {
126126
hint_warning: 'Avertissement',
127127
hint_danger: 'Danger',
128128
hint_success: 'Succès',
129+
download: 'Télécharger',
130+
open: 'Ouvrir',
129131
};

‎packages/gitbook/src/intl/translations/it.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,6 @@ export const it: TranslationLanguage = {
130130
hint_warning: 'Avviso',
131131
hint_danger: 'Pericolo',
132132
hint_success: 'Successo',
133+
download: 'Scarica',
134+
open: 'Apri',
133135
};

‎packages/gitbook/src/intl/translations/ja.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,6 @@ export const ja: TranslationLanguage = {
129129
hint_warning: '警告',
130130
hint_danger: '危険',
131131
hint_success: '成功',
132+
download: 'ダウンロード',
133+
open: '開く',
132134
};

‎packages/gitbook/src/intl/translations/nl.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,6 @@ export const nl: TranslationLanguage = {
129129
hint_warning: 'Waarschuwing',
130130
hint_danger: 'Gevaar',
131131
hint_success: 'Succes',
132+
download: 'Downloaden',
133+
open: 'Openen',
132134
};

‎packages/gitbook/src/intl/translations/no.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,6 @@ export const no: TranslationLanguage = {
130130
hint_warning: 'Advarsel',
131131
hint_danger: 'Fare',
132132
hint_success: 'Suksess',
133+
download: 'Last ned',
134+
open: 'Åpne',
133135
};

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /