diff --git a/apps/client/src/stylesheets/theme-next/base.css b/apps/client/src/stylesheets/theme-next/base.css index 7bf9423138..c1d3cc3094 100644 --- a/apps/client/src/stylesheets/theme-next/base.css +++ b/apps/client/src/stylesheets/theme-next/base.css @@ -544,14 +544,11 @@ li.dropdown-item a.dropdown-item-button:focus-visible { vertical-align: middle; } -#toast-container .toast .toast-header .btn-close { +#toast-container .toast .toast-header .btn-close, +#toast-container .toast .toast-close .btn-close { margin: 0 0 0 12px; } -#toast-container .toast.no-title { - flex-direction: row; -} - #toast-container .toast .toast-body { flex-grow: 1; overflow: hidden; diff --git a/apps/client/src/stylesheets/theme-next/dialogs.css b/apps/client/src/stylesheets/theme-next/dialogs.css index 613fb94f36..94b6ff21a1 100644 --- a/apps/client/src/stylesheets/theme-next/dialogs.css +++ b/apps/client/src/stylesheets/theme-next/dialogs.css @@ -26,7 +26,8 @@ .modal .modal-header .btn-close, .modal .modal-header .help-button, .modal .modal-header .custom-title-bar-button, -#toast-container .toast .toast-header .btn-close { +#toast-container .toast .toast-header .btn-close, +#toast-container .toast .toast-close .btn-close { display: flex; justify-content: center; align-items: center; @@ -46,12 +47,14 @@ } .modal .modal-header .btn-close, -#toast-container .toast .toast-header .btn-close { +#toast-container .toast .toast-header .btn-close, +#toast-container .toast .toast-close .btn-close { --modal-control-button-hover-background: var(--modal-close-button-hover-background); } .modal .modal-header .btn-close::after, -#toast-container .toast .toast-header .btn-close::after { +#toast-container .toast .toast-header .btn-close::after, +#toast-container .toast .toast-close .btn-close::after { content: "\ec8d"; font-family: boxicons; } @@ -67,7 +70,8 @@ .modal .modal-header .btn-close:hover, .modal .modal-header .help-button:hover, .modal .modal-header .custom-title-bar-button:hover, -#toast-container .toast .toast-header .btn-close:hover { +#toast-container .toast .toast-header .btn-close:hover, +#toast-container .toast .toast-close .btn-close:hover { background: var(--modal-control-button-hover-background); color: var(--modal-control-button-hover-color); } @@ -75,19 +79,22 @@ .modal .modal-header .btn-close:active, .modal .modal-header .help-button:active, .modal .modal-header .custom-title-bar-button:active, -#toast-container .toast .toast-header .btn-close:active { +#toast-container .toast .toast-header .btn-close:active, +#toast-container .toast .toast-close .btn-close:active { transform: scale(.85); } .modal .modal-header .btn-close:focus, .modal .modal-header .help-button:focus, -#toast-container .toast .toast-header .btn-close:focus { +#toast-container .toast .toast-header .btn-close:focus, +#toast-container .toast .toast-close .btn-close:focus { box-shadow: none !important; } .modal .modal-header .btn-close:focus-visible, .modal .modal-header .help-button:focus-visible, -#toast-container .toast .toast-header .btn-close:focus-visible { +#toast-container .toast .toast-header .btn-close:focus-visible, +#toast-container .toast .toast-close .btn-close:focus-visible { outline: 2px solid var(--input-focus-outline-color); outline-offset: 2px; } diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index f7ff29ae0c..e051f8f720 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2095,7 +2095,8 @@ "processing_started": "OCR processing has been started. Please wait a moment and refresh.", "processing_complete": "OCR processing complete.", "processing_failed": "Failed to start OCR processing", - "text_filtered_low_confidence": "OCR detected text with {{confidence}}% confidence, but it was discarded because your minimum threshold is {{threshold}}%.\n\nYou can adjust the threshold in Options → Media.", + "text_filtered_low_confidence": "OCR detected text with {{confidence}}% confidence, but it was discarded because your minimum threshold is {{threshold}}%.", + "open_media_settings": "Open Settings", "view_extracted_text": "View extracted text (OCR)" }, "command_palette": { diff --git a/apps/client/src/widgets/Toast.css b/apps/client/src/widgets/Toast.css index b58e6a13ab..95b9f69157 100644 --- a/apps/client/src/widgets/Toast.css +++ b/apps/client/src/widgets/Toast.css @@ -28,9 +28,10 @@ overflow: hidden; } -.toast.no-title { +.toast.no-title .toast-main-row { display: flex; flex-direction: row; + align-items: center; } .toast.no-title .toast-icon { @@ -40,22 +41,26 @@ } .toast.no-title .toast-body { - padding-inline-start: 0; - padding-inline-end: 0; + flex: 1; + padding-block: var(--bs-toast-padding-y); + padding-inline: 0; } -.toast.no-title .toast-header { - background-color: unset !important; +.toast.no-title .toast-close { + display: flex; + align-items: center; + padding: var(--bs-toast-padding-y) var(--bs-toast-padding-x); } .toast { .toast-buttons { - padding: 0 1em 1em 1em; + padding: 0 var(--bs-toast-padding-x) var(--bs-toast-padding-y) var(--bs-toast-padding-x); display: flex; - gap: 1em; - justify-content: space-between; + flex-direction: column; + gap: 0.5em; .btn { + width: 100%; color: var(--bs-toast-color); background: var(--modal-control-button-background); diff --git a/apps/client/src/widgets/type_widgets/ReadOnlyTextRepresentation.tsx b/apps/client/src/widgets/type_widgets/ReadOnlyTextRepresentation.tsx index c8f4340c32..a5bada9f6b 100644 --- a/apps/client/src/widgets/type_widgets/ReadOnlyTextRepresentation.tsx +++ b/apps/client/src/widgets/type_widgets/ReadOnlyTextRepresentation.tsx @@ -3,9 +3,11 @@ import "./ReadOnlyTextRepresentation.css"; import type { OCRProcessResponse, TextRepresentationResponse } from "@triliumnext/commons"; import { useEffect, useState } from "preact/hooks"; +import appContext from "../../components/app_context"; import { t } from "../../services/i18n"; import server from "../../services/server"; import toast from "../../services/toast"; +import { randomString } from "../../services/utils"; import { TypeWidgetProps } from "./type_widget"; type State = @@ -71,14 +73,22 @@ export function TextRepresentation({ textUrl, processUrl }: TextRepresentationPr if (result && !result.text && result.confidence > 0 && minConfidence > 0) { const confidencePercent = Math.round(result.confidence * 100); const thresholdPercent = Math.round(minConfidence * 100); - toast.showMessage( - t("ocr.text_filtered_low_confidence", { + toast.showPersistent({ + id: `ocr-low-confidence-${randomString(8)}`, + icon: "bx bx-info-circle", + message: t("ocr.text_filtered_low_confidence", { confidence: confidencePercent, threshold: thresholdPercent }), - 10000, // Show for 10 seconds since this is important info - "bx bx-info-circle" - ); + timeout: 15000, + buttons: [{ + text: t("ocr.open_media_settings"), + onClick: ({ dismissToast }) => { + appContext.tabManager.openInNewTab("_optionsMedia", null, true); + dismissToast(); + } + }] + }); } else { toast.showMessage(t("ocr.processing_complete")); }