Skip to content

Commit 6bac75c

Browse files
committed
Make fullscreen button optional and document it
1 parent fbe6958 commit 6bac75c

File tree

3 files changed

+28
-21
lines changed

3 files changed

+28
-21
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,13 @@ In the following table the list of parameters that can be provided to the `pdf_v
9898
| rendering | Type of rendering: `unwrap` (default), `legacy_iframe`, or `legacy_embed`. The default value, `unwrap` shows the PDF document using pdf.js, and supports the visualisation of annotations. Other values are `legacy_iframe` and `legacy_embed` which use the legacy approach of injecting the document into an `<embed>` or `<iframe>`. They allow viewing the PDF using the viewer of the browser that contains additional features we are still working to implement in this component. **IMPORTANT**: :warning: The "legacy" methods **work only with Firefox**, and **do not support annotations**. :warning: |
9999
| pages_to_render | Filter the rendering to a specific set of pages. By default, all pages are rendered. |
100100
| render_text | Enable a layer of text on top of the PDF document. The text may be selected and copied. **NOTE** to avoid breaking existing deployments, we made this optional at first, also considering that having many annotations might interfere with the copy-paste. |
101-
| zoom_level | The zoom level of the PDF viewer. Can be a float (0.1-10.0), `"auto"` for fit-to-width, `"auto-height"` for fit-to-height, or `None` (defaults to auto-fit to width). When zoom controls are enabled, users can interactively adjust the zoom level. |
102-
| viewer_align | The alignment of the PDF viewer within its container. Can be `"center"` (default), `"left"`, or `"right"`. |
101+
| zoom_level | The zoom level of the PDF viewer. Can be a float (0.1-10.0), `"auto"` for fit-to-width, `"auto-height"` for fit-to-height, or `None` (defaults to auto-fit to width). When zoom controls are enabled, users can interactively adjust the zoom level. |
102+
| viewer_align | The alignment of the PDF viewer within its container. Can be `"center"` (default), `"left"`, or `"right"`. |
103103
| show_page_separator | Whether to show a horizontal separator line between PDF pages. Defaults to `True`. |
104104
| scroll_to_page | Scroll to a specific page when the component is rendered. The parameter is an integer, which represent the positional value of the page. E.g. 1, will be the first page. Default is None. Require ints and ignores the parameters below zero. |
105105
| scroll_to_annotation | Scroll to a specific annotation when the component is rendered. The parameter is an integer, which represent the positional value of the annotation. E.g. 1, will be the first annotation. Default is None (don't scroll). Mutually exclusive with `scroll_to_page`. Raise an exception if used with `scroll_to_page` |
106106
| on_annotation_click | Callback function that is called when an annotation is clicked. The function receives the annotation as a parameter. |
107+
| show_fullscreen_toggle | Whether to show a button to toggle fullscreen mode. Defaults to `True`. |
107108

108109
### Annotation format
109110

streamlit_pdf_viewer/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def pdf_viewer(
4343
scroll_to_page: Optional[int] = None,
4444
scroll_to_annotation: Optional[int] = None,
4545
on_annotation_click: Optional[Callable[[dict], None]] = None,
46+
show_fullscreen_toggle: bool = True,
4647
):
4748
"""
4849
pdf_viewer function to display a PDF file in a Streamlit app.
@@ -67,6 +68,7 @@ def pdf_viewer(
6768
:param scroll_to_page: Scroll to a specific page in the PDF. The parameter is an integer, which represent the positional value of the page. E.g. 1, will be the first page. Defaults to None.
6869
:param scroll_to_annotation: Scroll to a specific annotation in the PDF. The parameter is an integer, which represent the positional value of the annotation. E.g. 1, will be the first annotation. Defaults to None.
6970
:param on_annotation_click: A callback function that will be called when an annotation is clicked. The function should accept a single argument, which is the annotation that was clicked. Defaults to None.
71+
:param show_fullscreen_toggle: Whether to show button to toggle fullscreen. Defaults to True.
7072
7173
The function reads the PDF file (from a file path, URL, or binary data), encodes it in base64,
7274
and uses a Streamlit component to render it in the app. It supports optional annotations and adjustable margins.
@@ -146,7 +148,8 @@ def pdf_viewer(
146148
viewer_align=viewer_align,
147149
show_page_separator=show_page_separator,
148150
scroll_to_page=scroll_to_page,
149-
scroll_to_annotation=scroll_to_annotation
151+
scroll_to_annotation=scroll_to_annotation,
152+
show_fullscreen_toggle=show_fullscreen_toggle,
150153
)
151154

152155
# Execute the custom callback function

streamlit_pdf_viewer/frontend/src/PdfViewer.vue

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@
1414
<div v-else>
1515
Error rendering option.
1616
</div>
17-
<div v-if="args.rendering === 'unwrap'" class="zoom-controls">
17+
<div v-if="args.rendering === 'unwrap'" class="control-buttons">
1818
<div class="top-buttons">
19-
<button class="zoom-button" @click.stop="toggleFullscreen" title="Toggle Fullscreen">
19+
<button v-if="showFullscreen" class="control-button" @click.stop="toggleFullscreen" title="Toggle Fullscreen">
2020
<svg v-if="!isFullscreen" style="width:16px; height:16px; vertical-align: middle;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/></svg>
2121
<svg v-else style="width:16px; height:16px; vertical-align: middle;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3"/></svg>
2222
</button>
23-
<button class="zoom-button" @click.stop="toggleZoomPanel">
23+
<button class="control-button" @click.stop="toggleZoomPanel">
2424
{{ Math.round(currentZoom * 100) }}%
2525
</button>
2626
</div>
2727
<div v-if="showZoomPanel" class="zoom-panel">
2828
<div class="zoom-input-container">
29-
<input
30-
type="number"
31-
class="zoom-input"
29+
<input
30+
type="number"
31+
class="zoom-input"
3232
v-model="manualZoomInput"
3333
@keyup.enter="applyManualZoom"
3434
@blur="applyManualZoom"
@@ -88,12 +88,14 @@ export default {
8888
const loadedPages = ref([]);
8989
const currentFrameHeight = ref(props.args.height || 0);
9090
const showZoomPanel = ref(false);
91-
const isFullscreen = ref(false);
92-
91+
9392
const initialZoom = props.args.zoom_level === null || props.args.zoom_level === undefined ? 'auto' : props.args.zoom_level;
9493
const localZoomLevel = ref(initialZoom);
9594
const currentZoom = ref(1); // Will be updated on render
96-
95+
96+
const isFullscreen = ref(false);
97+
const showFullscreen = props.args.show_fullscreen_toggle === true;
98+
9799
const zoomPresets = [0.5, 0.75, 1, 1.25, 1.5, 2];
98100
const pdfInstance = ref(null);
99101
const pdfContainer = ref(null);
@@ -124,7 +126,7 @@ export default {
124126
height: props.args.height ? `${props.args.height}px` : 'auto',
125127
position: 'relative',
126128
};
127-
129+
128130
const align = props.args.viewer_align || 'center';
129131
if (align === 'center') {
130132
style.marginLeft = 'auto';
@@ -136,7 +138,7 @@ export default {
136138
style.marginLeft = 'auto';
137139
style.marginRight = '0';
138140
}
139-
141+
140142
return style;
141143
});
142144
@@ -293,7 +295,7 @@ export default {
293295
for (let pageNumber = 1; pageNumber <= pdf.numPages; pageNumber++) {
294296
const page = await pdf.getPage(pageNumber);
295297
const rotation = page.rotate;
296-
298+
297299
pageScales.value.push(finalScale);
298300
pageHeights.value.push(page.getViewport({ scale: 1.0, rotation }).height);
299301
@@ -319,7 +321,7 @@ export default {
319321
}
320322
}
321323
}
322-
324+
323325
if (pagesToRender.length > 0) {
324326
totalHeight.value -= props.args.pages_vertical_spacing;
325327
}
@@ -418,7 +420,7 @@ export default {
418420
localZoomLevel.value = newVal === null || newVal === undefined ? 'auto' : newVal;
419421
handleResize();
420422
});
421-
423+
422424
watch(() => props.args.viewer_align, () => {
423425
handleResize();
424426
});
@@ -493,7 +495,7 @@ export default {
493495
};
494496
495497
const handleClickOutside = (event) => {
496-
if (showZoomPanel.value && !event.target.closest('.zoom-controls')) {
498+
if (showZoomPanel.value && !event.target.closest('.control-buttons')) {
497499
showZoomPanel.value = false;
498500
}
499501
};
@@ -532,6 +534,7 @@ export default {
532534
fitToHeight,
533535
toggleZoomPanel,
534536
applyManualZoom,
537+
showFullscreen,
535538
isFullscreen,
536539
toggleFullscreen,
537540
};
@@ -547,7 +550,7 @@ export default {
547550
height: 100%;
548551
overflow: auto;
549552
}
550-
.zoom-controls {
553+
.control-buttons {
551554
position: absolute;
552555
top: 20px;
553556
right: 20px;
@@ -563,7 +566,7 @@ export default {
563566
margin-bottom: 8px;
564567
}
565568
566-
.zoom-button {
569+
.control-button {
567570
background: rgba(40, 40, 40, 0.9);
568571
border: 1px solid rgba(255, 255, 255, 0.2);
569572
color: white;
@@ -576,7 +579,7 @@ export default {
576579
transition: background 0.2s;
577580
}
578581
579-
.zoom-button:hover {
582+
.control-button:hover {
580583
background: rgba(50, 50, 50, 0.9);
581584
}
582585

0 commit comments

Comments
 (0)