mirror of
https://github.com/zadam/trilium.git
synced 2025-11-10 15:25:51 +01:00
chore(react/type_widget): port file
This commit is contained in:
@@ -126,7 +126,7 @@ function downloadRevision(noteId: string, revisionId: string) {
|
|||||||
/**
|
/**
|
||||||
* @param url - should be without initial slash!!!
|
* @param url - should be without initial slash!!!
|
||||||
*/
|
*/
|
||||||
function getUrlForDownload(url: string) {
|
export function getUrlForDownload(url: string) {
|
||||||
if (utils.isElectron()) {
|
if (utils.isElectron()) {
|
||||||
// electron needs absolute URL, so we extract current host, port, protocol
|
// electron needs absolute URL, so we extract current host, port, protocol
|
||||||
return `${getHost()}/${url}`;
|
return `${getHost()}/${url}`;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import Book from "./type_widgets/Book";
|
|||||||
import ContentWidget from "./type_widgets/ContentWidget";
|
import ContentWidget from "./type_widgets/ContentWidget";
|
||||||
import WebView from "./type_widgets/WebView";
|
import WebView from "./type_widgets/WebView";
|
||||||
import "./NoteDetail.css";
|
import "./NoteDetail.css";
|
||||||
|
import File from "./type_widgets/File";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `NoteType` altered by the note detail widget, taking into consideration whether the note is editable or not and adding special note types such as an empty one,
|
* A `NoteType` altered by the note detail widget, taking into consideration whether the note is editable or not and adding special note types such as an empty one,
|
||||||
@@ -68,6 +69,7 @@ function getCorrespondingWidget(noteType: ExtendedNoteType | undefined, props: T
|
|||||||
case "book": return <Book {...props} />
|
case "book": return <Book {...props} />
|
||||||
case "contentWidget": return <ContentWidget {...props} />
|
case "contentWidget": return <ContentWidget {...props} />
|
||||||
case "webView": return <WebView {...props} />
|
case "webView": return <WebView {...props} />
|
||||||
|
case "file": return <File {...props} />
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
41
apps/client/src/widgets/type_widgets/File.css
Normal file
41
apps/client/src/widgets/type_widgets/File.css
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
.type-file .note-detail {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-detail-file {
|
||||||
|
padding: 10px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-split.full-content-width .note-detail-file {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-detail.full-height .note-detail-file[data-preview-type="pdf"],
|
||||||
|
.note-detail.full-height .note-detail-file[data-preview-type="video"] {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-preview-content {
|
||||||
|
background-color: var(--accented-background-color);
|
||||||
|
padding: 15px;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-detail-file > .pdf-preview,
|
||||||
|
.note-detail-file > .video-preview {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
flex-grow: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-detail-file > .audio-preview {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 15px;
|
||||||
|
right: 15px;
|
||||||
|
width: calc(100% - 30px);
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
86
apps/client/src/widgets/type_widgets/File.tsx
Normal file
86
apps/client/src/widgets/type_widgets/File.tsx
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import { VNode } from "preact";
|
||||||
|
import { useNoteBlob } from "../react/hooks";
|
||||||
|
import "./File.css";
|
||||||
|
import { TypeWidgetProps } from "./type_widget";
|
||||||
|
import FNote from "../../entities/fnote";
|
||||||
|
import { getUrlForDownload } from "../../services/open";
|
||||||
|
import Alert from "../react/Alert";
|
||||||
|
import { t } from "../../services/i18n";
|
||||||
|
|
||||||
|
const TEXT_MAX_NUM_CHARS = 5000;
|
||||||
|
|
||||||
|
export default function File({ note }: TypeWidgetProps) {
|
||||||
|
const blob = useNoteBlob(note);
|
||||||
|
|
||||||
|
let preview: VNode | null = null;
|
||||||
|
if (blob?.content) {
|
||||||
|
preview = <TextPreview content={blob.content} />
|
||||||
|
} else if (note.mime === "application/pdf") {
|
||||||
|
preview = <PdfPreview note={note} />
|
||||||
|
} else if (note.mime.startsWith("video/")) {
|
||||||
|
preview = <VideoPreview note={note} />
|
||||||
|
} else if (note.mime.startsWith("audio/")) {
|
||||||
|
preview = <AudioPreview note={note} />
|
||||||
|
} else {
|
||||||
|
preview = <NoPreview />
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="note-detail-file note-detail-printable">
|
||||||
|
{preview}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TextPreview({ content }: { content: string }) {
|
||||||
|
const trimmedContent = content.substring(0, TEXT_MAX_NUM_CHARS);
|
||||||
|
const isTooLarge = trimmedContent.length !== content.length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{isTooLarge && (
|
||||||
|
<Alert type="info">
|
||||||
|
{t("file.too_big", { maxNumChars: TEXT_MAX_NUM_CHARS })}
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
<pre class="file-preview-content">{trimmedContent}</pre>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function PdfPreview({ note }: { note: FNote }) {
|
||||||
|
return (
|
||||||
|
<iframe
|
||||||
|
class="pdf-preview"
|
||||||
|
src={getUrlForDownload(`api/notes/${note.noteId}/open`)} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function VideoPreview({ note }: { note: FNote }) {
|
||||||
|
return (
|
||||||
|
<video
|
||||||
|
class="video-preview"
|
||||||
|
src={getUrlForDownload(`api/notes/${note.noteId}/open-partial`)}
|
||||||
|
datatype={note?.mime}
|
||||||
|
controls
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function AudioPreview({ note }: { note: FNote }) {
|
||||||
|
return (
|
||||||
|
<audio
|
||||||
|
class="audio-preview"
|
||||||
|
src={getUrlForDownload(`api/notes/${note.noteId}/open-partial`)}
|
||||||
|
controls
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function NoPreview() {
|
||||||
|
return (
|
||||||
|
<Alert className="file-preview-not-available" type="info">
|
||||||
|
{t("file.file_preview_not_available")}
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
import openService from "../../services/open.js";
|
|
||||||
import TypeWidget from "./type_widget.js";
|
|
||||||
import { t } from "../../services/i18n.js";
|
|
||||||
import type { EventData } from "../../components/app_context.js";
|
|
||||||
import type FNote from "../../entities/fnote.js";
|
|
||||||
|
|
||||||
const TEXT_MAX_NUM_CHARS = 5000;
|
|
||||||
|
|
||||||
const TPL = /*html*/`
|
|
||||||
<div class="note-detail-file note-detail-printable">
|
|
||||||
<style>
|
|
||||||
.type-file .note-detail {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail-file {
|
|
||||||
padding: 10px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-split.full-content-width .note-detail-file {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail.full-height .note-detail-file[data-preview-type="pdf"],
|
|
||||||
.note-detail.full-height .note-detail-file[data-preview-type="video"] {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-preview-content {
|
|
||||||
background-color: var(--accented-background-color);
|
|
||||||
padding: 15px;
|
|
||||||
height: 100%;
|
|
||||||
overflow: auto;
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail-file > .video-preview {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="file-preview-too-big alert alert-info hidden-ext">
|
|
||||||
${t("file.too_big", { maxNumChars: TEXT_MAX_NUM_CHARS })}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<pre class="file-preview-content"></pre>
|
|
||||||
|
|
||||||
<div class="file-preview-not-available alert alert-info">
|
|
||||||
${t("file.file_preview_not_available")}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<iframe class="pdf-preview" style="width: 100%; height: 100%; flex-grow: 100;"></iframe>
|
|
||||||
|
|
||||||
<video class="video-preview" controls></video>
|
|
||||||
|
|
||||||
<audio class="audio-preview" controls></audio>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
export default class FileTypeWidget extends TypeWidget {
|
|
||||||
|
|
||||||
private $previewContent!: JQuery<HTMLElement>;
|
|
||||||
private $previewNotAvailable!: JQuery<HTMLElement>;
|
|
||||||
private $previewTooBig!: JQuery<HTMLElement>;
|
|
||||||
private $pdfPreview!: JQuery<HTMLElement>;
|
|
||||||
private $videoPreview!: JQuery<HTMLElement>;
|
|
||||||
private $audioPreview!: JQuery<HTMLElement>;
|
|
||||||
|
|
||||||
static getType() {
|
|
||||||
return "file";
|
|
||||||
}
|
|
||||||
|
|
||||||
doRender() {
|
|
||||||
this.$widget = $(TPL);
|
|
||||||
this.$previewContent = this.$widget.find(".file-preview-content");
|
|
||||||
this.$previewNotAvailable = this.$widget.find(".file-preview-not-available");
|
|
||||||
this.$previewTooBig = this.$widget.find(".file-preview-too-big");
|
|
||||||
this.$pdfPreview = this.$widget.find(".pdf-preview");
|
|
||||||
this.$videoPreview = this.$widget.find(".video-preview");
|
|
||||||
this.$audioPreview = this.$widget.find(".audio-preview");
|
|
||||||
|
|
||||||
super.doRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
async doRefresh(note: FNote) {
|
|
||||||
this.$widget.show();
|
|
||||||
|
|
||||||
const blob = await this.note?.getBlob();
|
|
||||||
|
|
||||||
this.$previewContent.empty().hide();
|
|
||||||
this.$pdfPreview.attr("src", "").empty().hide();
|
|
||||||
this.$previewNotAvailable.hide();
|
|
||||||
this.$previewTooBig.addClass("hidden-ext");
|
|
||||||
this.$videoPreview.hide();
|
|
||||||
this.$audioPreview.hide();
|
|
||||||
|
|
||||||
let previewType: string;
|
|
||||||
|
|
||||||
if (blob?.content) {
|
|
||||||
this.$previewContent.show().scrollTop(0);
|
|
||||||
const trimmedContent = blob.content.substring(0, TEXT_MAX_NUM_CHARS);
|
|
||||||
if (trimmedContent.length !== blob.content.length) {
|
|
||||||
this.$previewTooBig.removeClass("hidden-ext");
|
|
||||||
}
|
|
||||||
this.$previewContent.text(trimmedContent);
|
|
||||||
previewType = "text";
|
|
||||||
} else if (note.mime === "application/pdf") {
|
|
||||||
this.$pdfPreview.show().attr("src", openService.getUrlForDownload(`api/notes/${this.noteId}/open`));
|
|
||||||
previewType = "pdf";
|
|
||||||
} else if (note.mime.startsWith("video/")) {
|
|
||||||
this.$videoPreview
|
|
||||||
.show()
|
|
||||||
.attr("src", openService.getUrlForDownload(`api/notes/${this.noteId}/open-partial`))
|
|
||||||
.attr("type", this.note?.mime ?? "")
|
|
||||||
.css("width", this.$widget.width() ?? 0);
|
|
||||||
previewType = "video";
|
|
||||||
} else if (note.mime.startsWith("audio/")) {
|
|
||||||
this.$audioPreview
|
|
||||||
.show()
|
|
||||||
.attr("src", openService.getUrlForDownload(`api/notes/${this.noteId}/open-partial`))
|
|
||||||
.attr("type", this.note?.mime ?? "")
|
|
||||||
.css("width", this.$widget.width() ?? 0);
|
|
||||||
previewType = "audio";
|
|
||||||
} else {
|
|
||||||
this.$previewNotAvailable.show();
|
|
||||||
previewType = "not-available";
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$widget.attr("data-preview-type", previewType ?? "");
|
|
||||||
}
|
|
||||||
|
|
||||||
async entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
|
|
||||||
if (loadResults.isNoteReloaded(this.noteId)) {
|
|
||||||
this.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user