feat(print): display progress in toast

This commit is contained in:
Elian Doran 2025-11-21 12:24:01 +02:00
parent 6ca941e8e9
commit 586c707e51
No known key found for this signature in database
4 changed files with 40 additions and 18 deletions

View File

@ -8,46 +8,50 @@ export interface ToastOptions {
delay?: number; delay?: number;
autohide?: boolean; autohide?: boolean;
closeAfter?: number; closeAfter?: number;
progress?: number;
} }
function toast(options: ToastOptions) { function toast({ title, icon, message, id, delay, autohide, progress }: ToastOptions) {
const $toast = $(options.title const $toast = $(title
? `\ ? `\
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true"> <div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header"> <div class="toast-header">
<strong class="me-auto"> <strong class="me-auto">
<span class="bx bx-${options.icon}"></span> <span class="bx bx-${icon}"></span>
<span class="toast-title"></span> <span class="toast-title"></span>
</strong> </strong>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div> </div>
<div class="toast-body"></div> <div class="toast-body"></div>
<div class="toast-progress"></div>
</div>` </div>`
: ` : `
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true"> <div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-icon"> <div class="toast-icon">
<span class="bx bx-${options.icon}"></span> <span class="bx bx-${icon}"></span>
</div> </div>
<div class="toast-body"></div> <div class="toast-body"></div>
<div class="toast-header"> <div class="toast-header">
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div> </div>
<div class="toast-progress"></div>
</div>` </div>`
); );
$toast.toggleClass("no-title", !options.title); $toast.toggleClass("no-title", !title);
$toast.find(".toast-title").text(options.title ?? ""); $toast.find(".toast-title").text(title ?? "");
$toast.find(".toast-body").html(options.message); $toast.find(".toast-body").html(message);
$toast.find(".toast-progress").css("width", `${(progress ?? 0) * 100}%`);
if (options.id) { if (id) {
$toast.attr("id", `toast-${options.id}`); $toast.attr("id", `toast-${id}`);
} }
$("#toast-container").append($toast); $("#toast-container").append($toast);
$toast.toast({ $toast.toast({
delay: options.delay || 3000, delay: delay || 3000,
autohide: !!options.autohide autohide: !!autohide
}); });
$toast.on("hidden.bs.toast", (e) => e.target.remove()); $toast.on("hidden.bs.toast", (e) => e.target.remove());
@ -62,6 +66,7 @@ function showPersistent(options: ToastOptions) {
if ($toast.length > 0) { if ($toast.length > 0) {
$toast.find(".toast-body").html(options.message); $toast.find(".toast-body").html(options.message);
$toast.find(".toast-progress").css("width", `${(options.progress ?? 0) * 100}%`);
} else { } else {
options.autohide = false; options.autohide = false;

View File

@ -1137,6 +1137,7 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
--bs-toast-color: var(--main-text-color); --bs-toast-color: var(--main-text-color);
z-index: 9999999999 !important; z-index: 9999999999 !important;
pointer-events: all; pointer-events: all;
overflow: hidden;
} }
.toast-header { .toast-header {
@ -1169,6 +1170,16 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
background-color: unset !important; background-color: unset !important;
} }
.toast .toast-progress {
position: absolute;
bottom: 0;
inset-inline-start: 0;
inset-inline-end: 0;
background-color: var(--toast-text-color) !important;
height: 4px;
transition: width 0.1s linear;
}
.ck-mentions .ck-button { .ck-mentions .ck-button {
font-size: var(--detail-font-size) !important; font-size: var(--detail-font-size) !important;
padding: 5px; padding: 5px;

View File

@ -139,11 +139,7 @@ export default function NoteDetail() {
useTriliumEvent("printActiveNote", () => { useTriliumEvent("printActiveNote", () => {
if (!noteContext?.isActive() || !note) return; if (!noteContext?.isActive() || !note) return;
toast.showPersistent({ showToast("printing");
icon: "bx bx-loader-circle bx-spin",
message: t("note_detail.printing"),
id: "printing"
});
if (isElectron()) { if (isElectron()) {
const { ipcRenderer } = dynamicRequire("electron"); const { ipcRenderer } = dynamicRequire("electron");
@ -163,7 +159,7 @@ export default function NoteDetail() {
} }
iframe.contentWindow.addEventListener("note-load-progress", (e) => { iframe.contentWindow.addEventListener("note-load-progress", (e) => {
console.log("Got ", e); showToast("printing", e.detail.progress);
}); });
iframe.contentWindow.addEventListener("note-ready", () => { iframe.contentWindow.addEventListener("note-ready", () => {
@ -326,3 +322,12 @@ function checkFullHeight(noteContext: NoteContext | undefined, type: ExtendedNot
|| noteContext?.viewScope?.viewMode === "attachments" || noteContext?.viewScope?.viewMode === "attachments"
|| isBackendNote; || isBackendNote;
} }
function showToast(type: "printing" | "exporting_pdf", progress: number = 0) {
toast.showPersistent({
icon: "bx bx-loader-circle bx-spin",
message: t("note_detail.printing"),
id: "printing",
progress
});
}

View File

@ -18,6 +18,7 @@ export function ListPrintView({ note, noteIds: unfilteredNoteIds, onReady, onPro
const noteIdsSet = new Set<string>(); const noteIdsSet = new Set<string>();
froca.getNotes(noteIds).then(async (notes) => { froca.getNotes(noteIds).then(async (notes) => {
const noteIdsWithChildren = await note.getSubtreeNoteIds(true);
const notesWithContent: NotesWithContent[] = []; const notesWithContent: NotesWithContent[] = [];
async function processNote(note: FNote, depth: number) { async function processNote(note: FNote, depth: number) {
@ -34,7 +35,7 @@ export function ListPrintView({ note, noteIds: unfilteredNoteIds, onReady, onPro
notesWithContent.push({ note, contentEl }); notesWithContent.push({ note, contentEl });
if (onProgressChanged) { if (onProgressChanged) {
onProgressChanged((notesWithContent.length / noteIds.length) * 100); onProgressChanged(notesWithContent.length / noteIdsWithChildren.length);
} }
if (note.hasChildren()) { if (note.hasChildren()) {