mirror of
https://github.com/zadam/trilium.git
synced 2025-11-10 23:35:50 +01:00
chore(react/type_widget): start porting read-only text
This commit is contained in:
@@ -19,6 +19,7 @@ import { ReadOnlyCode, EditableCode } from "./type_widgets/code/Code";
|
|||||||
import Mermaid from "./type_widgets/Mermaid";
|
import Mermaid from "./type_widgets/Mermaid";
|
||||||
import MindMap from "./type_widgets/MindMap";
|
import MindMap from "./type_widgets/MindMap";
|
||||||
import { AttachmentDetail, AttachmentList } from "./type_widgets/Attachment";
|
import { AttachmentDetail, AttachmentList } from "./type_widgets/Attachment";
|
||||||
|
import ReadOnlyText from "./type_widgets/text/ReadOnlyText";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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,
|
||||||
@@ -101,6 +102,7 @@ function getCorrespondingWidget(noteType: ExtendedNoteType | undefined, props: T
|
|||||||
case "mindMap": return <MindMap {...props} />
|
case "mindMap": return <MindMap {...props} />
|
||||||
case "attachmentList": return <AttachmentList {...props} />
|
case "attachmentList": return <AttachmentList {...props} />
|
||||||
case "attachmentDetail": return <AttachmentDetail {...props} />
|
case "attachmentDetail": return <AttachmentDetail {...props} />
|
||||||
|
case "readOnlyText": return <ReadOnlyText {...props} />
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
58
apps/client/src/widgets/type_widgets/text/ReadOnlyText.css
Normal file
58
apps/client/src/widgets/type_widgets/text/ReadOnlyText.css
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/* h1 should not be used at all since semantically that's a note title */
|
||||||
|
.note-detail-readonly-text h1 { font-size: 1.8em; }
|
||||||
|
.note-detail-readonly-text h2 { font-size: 1.6em; }
|
||||||
|
.note-detail-readonly-text h3 { font-size: 1.4em; }
|
||||||
|
.note-detail-readonly-text h4 { font-size: 1.2em; }
|
||||||
|
.note-detail-readonly-text h5 { font-size: 1.1em; }
|
||||||
|
.note-detail-readonly-text h6 { font-size: 1.0em; }
|
||||||
|
|
||||||
|
body.heading-style-markdown .note-detail-readonly-text h1::before { content: "#\\2004"; color: var(--muted-text-color); }
|
||||||
|
body.heading-style-markdown .note-detail-readonly-text h2::before { content: "##\\2004"; color: var(--muted-text-color); }
|
||||||
|
body.heading-style-markdown .note-detail-readonly-text h3::before { content: "###\\2004"; color: var(--muted-text-color); }
|
||||||
|
body.heading-style-markdown .note-detail-readonly-text h4:not(.include-note-title)::before { content: "####\\2004"; color: var(--muted-text-color); }
|
||||||
|
body.heading-style-markdown .note-detail-readonly-text h5::before { content: "#####\\2004"; color: var(--muted-text-color); }
|
||||||
|
body.heading-style-markdown .note-detail-readonly-text h6::before { content: "######\\2004"; color: var(--muted-text-color); }
|
||||||
|
|
||||||
|
body.heading-style-underline .note-detail-readonly-text h1 { border-bottom: 1px solid var(--main-border-color); }
|
||||||
|
body.heading-style-underline .note-detail-readonly-text h2 { border-bottom: 1px solid var(--main-border-color); }
|
||||||
|
body.heading-style-underline .note-detail-readonly-text h3 { border-bottom: 1px solid var(--main-border-color); }
|
||||||
|
body.heading-style-underline .note-detail-readonly-text h4:not(.include-note-title) { border-bottom: 1px solid var(--main-border-color); }
|
||||||
|
body.heading-style-underline .note-detail-readonly-text h5 { border-bottom: 1px solid var(--main-border-color); }
|
||||||
|
body.heading-style-underline .note-detail-readonly-text h6 { border-bottom: 1px solid var(--main-border-color); }
|
||||||
|
|
||||||
|
.note-detail-readonly-text {
|
||||||
|
padding-inline-start: 24px;
|
||||||
|
padding-top: 10px;
|
||||||
|
font-family: var(--detail-font-family);
|
||||||
|
min-height: 50px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mobile .note-detail-readonly-text {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-detail-readonly-text p:first-child, .note-detail-readonly-text::before {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-detail-readonly-text img {
|
||||||
|
max-width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-text-note-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 10px;
|
||||||
|
font-size: 150%;
|
||||||
|
padding: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: var(--button-border-radius);
|
||||||
|
color: var(--button-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-text-note-button:hover {
|
||||||
|
border-color: var(--button-border-color);
|
||||||
|
}
|
||||||
41
apps/client/src/widgets/type_widgets/text/ReadOnlyText.tsx
Normal file
41
apps/client/src/widgets/type_widgets/text/ReadOnlyText.tsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { useEffect, useMemo, useRef } from "preact/hooks";
|
||||||
|
import { TypeWidgetProps } from "../type_widget";
|
||||||
|
import "./ReadOnlyText.css";
|
||||||
|
import { useNoteBlob, useNoteLabel } from "../../react/hooks";
|
||||||
|
import RawHtml from "../../react/RawHtml";
|
||||||
|
|
||||||
|
// we load CKEditor also for read only notes because they contain content styles required for correct rendering of even read only notes
|
||||||
|
// we could load just ckeditor-content.css but that causes CSS conflicts when both build CSS and this content CSS is loaded at the same time
|
||||||
|
// (see https://github.com/zadam/trilium/issues/1590 for example of such conflict)
|
||||||
|
import "@triliumnext/ckeditor5";
|
||||||
|
import FNote from "../../../entities/fnote";
|
||||||
|
import { getLocaleById } from "../../../services/i18n";
|
||||||
|
|
||||||
|
export default function ReadOnlyText({ note }: TypeWidgetProps) {
|
||||||
|
const blob = useNoteBlob(note);
|
||||||
|
const contentRef = useRef<HTMLDivElement>(null);
|
||||||
|
const { isRtl } = useNoteLanguage(note);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="note-detail-readonly-text note-detail-printable"
|
||||||
|
tabindex={100}
|
||||||
|
dir={isRtl ? "rtl" : "ltr"}
|
||||||
|
>
|
||||||
|
<RawHtml
|
||||||
|
containerRef={contentRef}
|
||||||
|
className="note-detail-readonly-text-content ck-content use-tn-links"
|
||||||
|
html={blob?.content}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function useNoteLanguage(note: FNote) {
|
||||||
|
const [ language ] = useNoteLabel(note, "language");
|
||||||
|
const isRtl = useMemo(() => {
|
||||||
|
const correspondingLocale = getLocaleById(language);
|
||||||
|
return correspondingLocale?.rtl;
|
||||||
|
}, [ language ]);
|
||||||
|
return { isRtl };
|
||||||
|
}
|
||||||
@@ -2,78 +2,10 @@ import AbstractTextTypeWidget from "./abstract_text_type_widget.js";
|
|||||||
import { formatCodeBlocks } from "../../services/syntax_highlight.js";
|
import { formatCodeBlocks } from "../../services/syntax_highlight.js";
|
||||||
import type FNote from "../../entities/fnote.js";
|
import type FNote from "../../entities/fnote.js";
|
||||||
import type { CommandListenerData, EventData } from "../../components/app_context.js";
|
import type { CommandListenerData, EventData } from "../../components/app_context.js";
|
||||||
import { getLocaleById } from "../../services/i18n.js";
|
|
||||||
import appContext from "../../components/app_context.js";
|
import appContext from "../../components/app_context.js";
|
||||||
import { getMermaidConfig } from "../../services/mermaid.js";
|
import { getMermaidConfig } from "../../services/mermaid.js";
|
||||||
import { renderMathInElement } from "../../services/math.js";
|
import { renderMathInElement } from "../../services/math.js";
|
||||||
|
|
||||||
const TPL = /*html*/`
|
|
||||||
<div class="note-detail-readonly-text note-detail-printable" tabindex="100">
|
|
||||||
<style>
|
|
||||||
/* h1 should not be used at all since semantically that's a note title */
|
|
||||||
.note-detail-readonly-text h1 { font-size: 1.8em; }
|
|
||||||
.note-detail-readonly-text h2 { font-size: 1.6em; }
|
|
||||||
.note-detail-readonly-text h3 { font-size: 1.4em; }
|
|
||||||
.note-detail-readonly-text h4 { font-size: 1.2em; }
|
|
||||||
.note-detail-readonly-text h5 { font-size: 1.1em; }
|
|
||||||
.note-detail-readonly-text h6 { font-size: 1.0em; }
|
|
||||||
|
|
||||||
body.heading-style-markdown .note-detail-readonly-text h1::before { content: "#\\2004"; color: var(--muted-text-color); }
|
|
||||||
body.heading-style-markdown .note-detail-readonly-text h2::before { content: "##\\2004"; color: var(--muted-text-color); }
|
|
||||||
body.heading-style-markdown .note-detail-readonly-text h3::before { content: "###\\2004"; color: var(--muted-text-color); }
|
|
||||||
body.heading-style-markdown .note-detail-readonly-text h4:not(.include-note-title)::before { content: "####\\2004"; color: var(--muted-text-color); }
|
|
||||||
body.heading-style-markdown .note-detail-readonly-text h5::before { content: "#####\\2004"; color: var(--muted-text-color); }
|
|
||||||
body.heading-style-markdown .note-detail-readonly-text h6::before { content: "######\\2004"; color: var(--muted-text-color); }
|
|
||||||
|
|
||||||
body.heading-style-underline .note-detail-readonly-text h1 { border-bottom: 1px solid var(--main-border-color); }
|
|
||||||
body.heading-style-underline .note-detail-readonly-text h2 { border-bottom: 1px solid var(--main-border-color); }
|
|
||||||
body.heading-style-underline .note-detail-readonly-text h3 { border-bottom: 1px solid var(--main-border-color); }
|
|
||||||
body.heading-style-underline .note-detail-readonly-text h4:not(.include-note-title) { border-bottom: 1px solid var(--main-border-color); }
|
|
||||||
body.heading-style-underline .note-detail-readonly-text h5 { border-bottom: 1px solid var(--main-border-color); }
|
|
||||||
body.heading-style-underline .note-detail-readonly-text h6 { border-bottom: 1px solid var(--main-border-color); }
|
|
||||||
|
|
||||||
.note-detail-readonly-text {
|
|
||||||
padding-inline-start: 24px;
|
|
||||||
padding-top: 10px;
|
|
||||||
font-family: var(--detail-font-family);
|
|
||||||
min-height: 50px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.mobile .note-detail-readonly-text {
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail-readonly-text p:first-child, .note-detail-readonly-text::before {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail-readonly-text img {
|
|
||||||
max-width: 100%;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-text-note-button {
|
|
||||||
position: absolute;
|
|
||||||
top: 5px;
|
|
||||||
right: 10px;
|
|
||||||
font-size: 150%;
|
|
||||||
padding: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: var(--button-border-radius);
|
|
||||||
color: var(--button-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-text-note-button:hover {
|
|
||||||
border-color: var(--button-border-color);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="note-detail-readonly-text-content ck-content use-tn-links"></div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
|
export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
|
||||||
|
|
||||||
private $content!: JQuery<HTMLElement>;
|
private $content!: JQuery<HTMLElement>;
|
||||||
@@ -83,8 +15,6 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
doRender() {
|
doRender() {
|
||||||
this.$widget = $(TPL);
|
|
||||||
|
|
||||||
this.$content = this.$widget.find(".note-detail-readonly-text-content");
|
this.$content = this.$widget.find(".note-detail-readonly-text-content");
|
||||||
|
|
||||||
this.setupImageOpening(true);
|
this.setupImageOpening(true);
|
||||||
@@ -97,11 +27,6 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async doRefresh(note: FNote) {
|
async doRefresh(note: FNote) {
|
||||||
// we load CKEditor also for read only notes because they contain content styles required for correct rendering of even read only notes
|
|
||||||
// we could load just ckeditor-content.css but that causes CSS conflicts when both build CSS and this content CSS is loaded at the same time
|
|
||||||
// (see https://github.com/zadam/trilium/issues/1590 for example of such conflict)
|
|
||||||
await import("@triliumnext/ckeditor5");
|
|
||||||
|
|
||||||
this.onLanguageChanged();
|
this.onLanguageChanged();
|
||||||
|
|
||||||
const blob = await note.getBlob();
|
const blob = await note.getBlob();
|
||||||
@@ -161,13 +86,6 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
resolve(this.$content);
|
resolve(this.$content);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onLanguageChanged(): Promise<void> {
|
|
||||||
const languageCode = this.note?.getLabelValue("language");
|
|
||||||
const correspondingLocale = getLocaleById(languageCode);
|
|
||||||
const isRtl = correspondingLocale?.rtl;
|
|
||||||
this.$widget.attr("dir", isRtl ? "rtl" : "ltr");
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) {
|
buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) {
|
||||||
return [
|
return [
|
||||||
new TouchBar.TouchBarSpacer({ size: "flexible" }),
|
new TouchBar.TouchBarSpacer({ size: "flexible" }),
|
||||||
|
|||||||
Reference in New Issue
Block a user