feat(pdf-viewer): enhance PDF viewer with file size display and footer layout

This commit is contained in:
2026-04-03 19:50:46 +00:00
parent 02522c9a15
commit 3defbba5fd
3 changed files with 125 additions and 22 deletions

View File

@@ -3,6 +3,7 @@ import { PdfManager } from '../dees-pdf-shared/PdfManager.js';
import { viewerStyles } from './styles.js'; import { viewerStyles } from './styles.js';
import { demo as demoFunc } from './demo.js'; import { demo as demoFunc } from './demo.js';
import '../../00group-utility/dees-icon/dees-icon.js'; import '../../00group-utility/dees-icon/dees-icon.js';
import '../../00group-layout/dees-tile/dees-tile.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -54,6 +55,9 @@ export class DeesPdfViewer extends DeesElement {
@property({ type: Array }) @property({ type: Array })
accessor pageData: Array<{page: number, rendered: boolean, rendering: boolean, textLayerRendered: boolean}> = []; accessor pageData: Array<{page: number, rendered: boolean, rendering: boolean, textLayerRendered: boolean}> = [];
@property({ type: Number })
accessor pdfFileSize: number = 0;
private pdfDocument: any; private pdfDocument: any;
private renderState: RenderState = 'idle'; private renderState: RenderState = 'idle';
private renderAbortController: AbortController | null = null; private renderAbortController: AbortController | null = null;
@@ -85,9 +89,9 @@ export class DeesPdfViewer extends DeesElement {
public render(): TemplateResult { public render(): TemplateResult {
return html` return html`
<div class="pdf-viewer ${this.showSidebar ? 'with-sidebar' : ''}"> <dees-tile class="${this.showSidebar ? 'with-sidebar' : ''}">
${this.showToolbar ? html` ${this.showToolbar ? html`
<div class="toolbar"> <div slot="header" class="toolbar">
<div class="toolbar-group"> <div class="toolbar-group">
<button <button
class="toolbar-button" class="toolbar-button"
@@ -240,7 +244,23 @@ export class DeesPdfViewer extends DeesElement {
`} `}
</div> </div>
</div> </div>
</div> <div slot="footer" class="pdf-footer">
<div class="pdf-footer-left">
<span class="pdf-footer-item">Zoom ${Math.round(this.currentZoom * 100)}%</span>
${this.pdfFileSize > 0 ? html`
<span class="pdf-footer-item">${this.formatFileSize(this.pdfFileSize)}</span>
` : ''}
</div>
<div class="pdf-footer-center" style="margin-left: ${this.showSidebar ? '100px' : '0'}">
<span>Page ${this.currentPage} of ${this.totalPages}</span>
</div>
<div class="pdf-footer-right">
${this.pdfUrl ? html`
<span class="pdf-footer-filename">${this.pdfUrl.split('/').pop()}</span>
` : ''}
</div>
</div>
</dees-tile>
`; `;
} }
@@ -305,6 +325,12 @@ export class DeesPdfViewer extends DeesElement {
} }
} }
private formatFileSize(bytes: number): string {
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}
private async loadPdf() { private async loadPdf() {
this.loading = true; this.loading = true;
this.renderState = 'loading'; this.renderState = 'loading';
@@ -323,6 +349,14 @@ export class DeesPdfViewer extends DeesElement {
this.currentPage = this.initialPage; this.currentPage = this.initialPage;
this.resolveInitialViewportMode(); this.resolveInitialViewportMode();
// Get file size
try {
const data = await this.pdfDocument.getData();
this.pdfFileSize = data.length;
} catch (e) {
this.pdfFileSize = 0;
}
// Initialize thumbnail and page data arrays // Initialize thumbnail and page data arrays
this.thumbnailData = Array.from({length: this.totalPages}, (_, i) => ({ this.thumbnailData = Array.from({length: this.totalPages}, (_, i) => ({
page: i + 1, page: i + 1,

View File

@@ -3,8 +3,8 @@ import { html } from '@design.estate/dees-element';
export const demo = () => html` export const demo = () => html`
<style> <style>
.demo-container { .demo-container {
padding: 40px; padding: 20px;
background: #f5f5f5; background: #000000;
} }
.demo-section { .demo-section {
@@ -15,6 +15,7 @@ export const demo = () => html`
margin-bottom: 20px; margin-bottom: 20px;
font-size: 18px; font-size: 18px;
font-weight: 600; font-weight: 600;
color: #fafafa;
} }
dees-pdf-viewer { dees-pdf-viewer {

View File

@@ -12,25 +12,47 @@ export const viewerStyles = [
contain: layout style; contain: layout style;
} }
.pdf-viewer { dees-tile {
width: 100%;
height: 100%; height: 100%;
display: flex; }
flex-direction: column;
background: ${cssManager.bdTheme('hsl(0 0% 97%)', 'hsl(215 20% 10%)')}; .viewer-container::before,
position: relative; .viewer-container::after {
overflow: hidden; content: '';
position: absolute;
left: 0;
right: 0;
height: 8px;
z-index: 5;
pointer-events: none;
}
.viewer-container::before {
top: 0;
background: linear-gradient(
to bottom,
${cssManager.bdTheme('hsl(0 0% 0% / 0.08)', 'hsl(0 0% 0% / 0.4)')},
${cssManager.bdTheme('hsl(0 0% 0% / 0.03)', 'hsl(0 0% 0% / 0.12)')},
transparent
);
}
.viewer-container::after {
bottom: 0;
background: linear-gradient(
to top,
${cssManager.bdTheme('hsl(0 0% 0% / 0.08)', 'hsl(0 0% 0% / 0.4)')},
${cssManager.bdTheme('hsl(0 0% 0% / 0.03)', 'hsl(0 0% 0% / 0.12)')},
transparent
);
} }
.toolbar { .toolbar {
height: 48px; height: 40px;
background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(215 20% 15%)')};
border-bottom: 1px solid ${cssManager.bdTheme('hsl(214 31% 91%)', 'hsl(217 25% 22%)')};
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0 16px; padding: 0 12px;
gap: 16px; gap: 12px;
flex-shrink: 0;
} }
.toolbar-group { .toolbar-group {
@@ -108,16 +130,15 @@ export const viewerStyles = [
} }
.viewer-container { .viewer-container {
flex: 1; position: absolute;
inset: 0;
display: flex; display: flex;
overflow: hidden; overflow: hidden;
position: relative;
min-height: 0;
} }
.sidebar { .sidebar {
width: 200px; width: 200px;
background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(215 20% 15%)')}; background: transparent;
border-right: 1px solid ${cssManager.bdTheme('hsl(214 31% 91%)', 'hsl(217 25% 22%)')}; border-right: 1px solid ${cssManager.bdTheme('hsl(214 31% 91%)', 'hsl(217 25% 22%)')};
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -334,5 +355,52 @@ export const viewerStyles = [
.pdf-viewer.with-sidebar .viewer-main { .pdf-viewer.with-sidebar .viewer-main {
margin-left: 0; margin-left: 0;
} }
.pdf-footer {
height: 28px;
padding: 0 16px;
display: flex;
align-items: center;
font-size: 11px;
color: ${cssManager.bdTheme('hsl(0 0% 45%)', 'hsl(0 0% 55%)')};
width: 100%;
box-sizing: border-box;
position: relative;
}
.pdf-footer-left {
display: flex;
align-items: center;
gap: 12px;
}
.pdf-footer-left .pdf-footer-item + .pdf-footer-item {
padding-left: 12px;
border-left: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
}
.pdf-footer-center {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-weight: 500;
transition: margin-left 0.15s ease;
}
.pdf-footer-right {
margin-left: auto;
}
.pdf-footer-item {
white-space: nowrap;
}
.pdf-footer-filename {
font-family: 'Intel One Mono', 'Geist Mono', monospace;
opacity: 0.7;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
`, `,
]; ];