mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-29 19:55:20 +00:00
UBERF-9343 Refactor PDF viewer components (#7901)
Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
parent
8a6232713c
commit
8f195c66c2
@ -13,7 +13,7 @@
|
||||
|
||||
"DESKTOP_UPDATES_CHANNEL": "front",
|
||||
|
||||
"FILES_URL": "https://dl.hc.engineering/blob/:workspace/:blobId",
|
||||
"FILES_URL": "https://dl.hc.engineering/blob/:workspace/:blobId/:filename",
|
||||
|
||||
"GITHUB_APP": "huly-github-staging",
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
// import { Doc } from '@hcengineering/core'
|
||||
import type { Blob, Ref } from '@hcengineering/core'
|
||||
import { Button, Dialog, Label, Spinner } from '@hcengineering/ui'
|
||||
import { Button, Dialog, EmbeddedPDF, Label, Spinner } from '@hcengineering/ui'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import presentation, { getFileUrl } from '..'
|
||||
import ActionContext from './ActionContext.svelte'
|
||||
@ -45,22 +45,9 @@
|
||||
})
|
||||
let download: HTMLAnchorElement
|
||||
|
||||
$: srcRef = file !== undefined ? getFileUrl(file, name) : undefined
|
||||
$: src = file !== undefined ? getFileUrl(file, name) : undefined
|
||||
|
||||
$: isImage = contentType !== undefined && contentType.startsWith('image/')
|
||||
|
||||
let frame: HTMLIFrameElement | undefined = undefined
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||
$: if (css !== undefined && frame !== undefined && frame !== null) {
|
||||
frame.onload = () => {
|
||||
const head = frame?.contentDocument?.querySelector('head')
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||
if (css !== undefined && head !== undefined && head !== null) {
|
||||
head.appendChild(document.createElement('style')).textContent = css
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<ActionContext context={{ mode: 'browser' }} />
|
||||
@ -85,41 +72,37 @@
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="utils">
|
||||
{#await srcRef then src}
|
||||
{#if !isLoading && src !== ''}
|
||||
<a class="no-line" href={src} download={name} bind:this={download}>
|
||||
<Button
|
||||
icon={Download}
|
||||
kind={'ghost'}
|
||||
on:click={() => {
|
||||
download.click()
|
||||
}}
|
||||
showTooltip={{ label: presentation.string.Download }}
|
||||
/>
|
||||
</a>
|
||||
{/if}
|
||||
{/await}
|
||||
{#if !isLoading && src !== ''}
|
||||
<a class="no-line" href={src} download={name} bind:this={download}>
|
||||
<Button
|
||||
icon={Download}
|
||||
kind={'ghost'}
|
||||
on:click={() => {
|
||||
download.click()
|
||||
}}
|
||||
showTooltip={{ label: presentation.string.Download }}
|
||||
/>
|
||||
</a>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
{#await srcRef then src}
|
||||
{#if !isLoading}
|
||||
{#if src === '' || src === undefined}
|
||||
<div class="centered">
|
||||
<Label label={presentation.string.FailedToPreview} />
|
||||
</div>
|
||||
{:else if isImage}
|
||||
<div class="pdfviewer-content img">
|
||||
<img class="img-fit" {src} alt="" />
|
||||
</div>
|
||||
{:else}
|
||||
<iframe bind:this={frame} class="pdfviewer-content" src={src + '#view=FitH&navpanes=0'} title="" />
|
||||
{/if}
|
||||
{:else}
|
||||
{#if !isLoading}
|
||||
{#if src === '' || src === undefined}
|
||||
<div class="centered">
|
||||
<Spinner size="medium" />
|
||||
<Label label={presentation.string.FailedToPreview} />
|
||||
</div>
|
||||
{:else if isImage}
|
||||
<div class="pdfviewer-content img">
|
||||
<img class="img-fit" {src} alt="" />
|
||||
</div>
|
||||
{:else}
|
||||
<EmbeddedPDF {src} {name} {css} fit />
|
||||
{/if}
|
||||
{/await}
|
||||
{:else}
|
||||
<div class="centered">
|
||||
<Spinner size="medium" />
|
||||
</div>
|
||||
{/if}
|
||||
</Dialog>
|
||||
|
||||
<style lang="scss">
|
||||
|
88
packages/ui/src/components/EmbeddedPDF.svelte
Normal file
88
packages/ui/src/components/EmbeddedPDF.svelte
Normal file
@ -0,0 +1,88 @@
|
||||
<!--
|
||||
// Copyright © 2025 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { onDestroy } from 'svelte'
|
||||
import Loading from './Loading.svelte'
|
||||
|
||||
export let src: string
|
||||
export let name: string
|
||||
export let fit: boolean = false
|
||||
export let css: string | undefined = undefined
|
||||
|
||||
let iframeSrc: string | undefined = undefined
|
||||
|
||||
async function loadFile (src: string): Promise<void> {
|
||||
if (iframeSrc !== undefined) {
|
||||
URL.revokeObjectURL(iframeSrc)
|
||||
iframeSrc = undefined
|
||||
}
|
||||
|
||||
const response = await fetch(src)
|
||||
const blob = await response.blob()
|
||||
iframeSrc = URL.createObjectURL(blob)
|
||||
}
|
||||
|
||||
$: void loadFile(src)
|
||||
|
||||
let iframe: HTMLIFrameElement | undefined = undefined
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||
$: if (css !== undefined && iframe !== undefined && iframe !== null) {
|
||||
iframe.onload = () => {
|
||||
const head = iframe?.contentDocument?.querySelector('head')
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||
if (css !== undefined && head !== undefined && head !== null) {
|
||||
head.appendChild(document.createElement('style')).textContent = css
|
||||
}
|
||||
}
|
||||
|
||||
if (iframe.contentDocument !== undefined) {
|
||||
const style = iframe.contentDocument?.querySelector('head style')
|
||||
|
||||
if (style != null) {
|
||||
style.textContent = css
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (iframeSrc !== undefined) {
|
||||
URL.revokeObjectURL(iframeSrc)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if iframeSrc}
|
||||
<iframe bind:this={iframe} class:fit src={iframeSrc + '#view=FitH&navpanes=0'} title={name} on:load />
|
||||
{:else}
|
||||
<Loading />
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
iframe {
|
||||
width: 100%;
|
||||
border: none;
|
||||
|
||||
&.fit {
|
||||
min-height: 100%;
|
||||
}
|
||||
&:not(.fit) {
|
||||
height: 80vh;
|
||||
min-height: 20rem;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -280,6 +280,7 @@ export { default as CodeForm } from './components/CodeForm.svelte'
|
||||
export { default as CodeInput } from './components/CodeInput.svelte'
|
||||
export { default as TimeLeft } from './components/TimeLeft.svelte'
|
||||
export { default as SectionEmpty } from './components/SectionEmpty.svelte'
|
||||
export { default as EmbeddedPDF } from './components/EmbeddedPDF.svelte'
|
||||
|
||||
export { default as Dock } from './components/Dock.svelte'
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
import { type Blob, type Ref } from '@hcengineering/core'
|
||||
import { getMetadata } from '@hcengineering/platform'
|
||||
import presentation, { BlobMetadata, getFileUrl } from '@hcengineering/presentation'
|
||||
import { Spinner, themeStore } from '@hcengineering/ui'
|
||||
import { EmbeddedPDF, Spinner, themeStore } from '@hcengineering/ui'
|
||||
import { convertToHTML } from '@hcengineering/print'
|
||||
|
||||
export let value: Ref<Blob>
|
||||
@ -55,7 +55,6 @@
|
||||
--scrollbar-bar-color: #e0e0e0;
|
||||
--scrollbar-bar-hover: #90959d;
|
||||
`
|
||||
let oldColors = colors
|
||||
|
||||
$: css = `
|
||||
* {
|
||||
@ -262,29 +261,6 @@
|
||||
border-radius: 2px;
|
||||
}
|
||||
`
|
||||
|
||||
let frame: HTMLIFrameElement | undefined = undefined
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||
$: if (css !== undefined && frame !== undefined && frame !== null) {
|
||||
frame.onload = () => {
|
||||
const head = frame?.contentDocument?.querySelector('head')
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||
if (css !== undefined && head !== undefined && head !== null) {
|
||||
head.appendChild(document.createElement('style')).textContent = css
|
||||
oldColors = colors
|
||||
}
|
||||
}
|
||||
}
|
||||
$: if (oldColors !== colors && css !== undefined && frame != null) {
|
||||
const style = frame?.contentDocument?.querySelector('head style')
|
||||
|
||||
if (style != null) {
|
||||
style.textContent = css
|
||||
oldColors = colors
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if src}
|
||||
@ -293,7 +269,7 @@
|
||||
<Spinner size="medium" />
|
||||
</div>
|
||||
{:else}
|
||||
<iframe bind:this={frame} src={src + '#view=FitH&navpanes=0'} class="w-full h-full" title={name} />
|
||||
<EmbeddedPDF {src} {name} {css} />
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
|
@ -15,25 +15,11 @@
|
||||
<script lang="ts">
|
||||
import { type Blob, type Ref } from '@hcengineering/core'
|
||||
import { getFileUrl } from '@hcengineering/presentation'
|
||||
import { EmbeddedPDF } from '@hcengineering/ui'
|
||||
|
||||
export let value: Ref<Blob>
|
||||
export let name: string
|
||||
export let fit: boolean = false
|
||||
</script>
|
||||
|
||||
<iframe class:fit src={getFileUrl(value, name) + '#view=FitH&navpanes=0'} title={name} />
|
||||
|
||||
<style lang="scss">
|
||||
iframe {
|
||||
width: 100%;
|
||||
border: none;
|
||||
|
||||
&.fit {
|
||||
min-height: 100%;
|
||||
}
|
||||
&:not(.fit) {
|
||||
height: 80vh;
|
||||
min-height: 20rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<EmbeddedPDF src={getFileUrl(value, name)} {name} {fit} />
|
||||
|
Loading…
Reference in New Issue
Block a user