mirror of
https://github.com/zadam/trilium.git
synced 2025-11-11 07:45:51 +01:00
refactor(react/type_widgets): deduplicate containers
This commit is contained in:
@@ -103,6 +103,7 @@ export default function NoteDetail() {
|
|||||||
key={type}
|
key={type}
|
||||||
type={type as ExtendedNoteType}
|
type={type as ExtendedNoteType}
|
||||||
isVisible={activeNoteType === type}
|
isVisible={activeNoteType === type}
|
||||||
|
isFullHeight={isFullHeight}
|
||||||
props={props}
|
props={props}
|
||||||
/>
|
/>
|
||||||
})}
|
})}
|
||||||
@@ -114,7 +115,7 @@ export default function NoteDetail() {
|
|||||||
* Wraps a single note type widget, in order to keep it in the DOM even after the user has switched away to another note type. This allows faster loading of the same note type again. The properties are cached, so that they are updated only
|
* Wraps a single note type widget, in order to keep it in the DOM even after the user has switched away to another note type. This allows faster loading of the same note type again. The properties are cached, so that they are updated only
|
||||||
* while the widget is visible, to avoid rendering in the background. When not visible, the DOM element is simply hidden.
|
* while the widget is visible, to avoid rendering in the background. When not visible, the DOM element is simply hidden.
|
||||||
*/
|
*/
|
||||||
function NoteDetailWrapper({ Element, type, isVisible, props }: { Element: (props: TypeWidgetProps) => VNode, type: ExtendedNoteType, isVisible: boolean, props: TypeWidgetProps }) {
|
function NoteDetailWrapper({ Element, type, isVisible, isFullHeight, props }: { Element: (props: TypeWidgetProps) => VNode, type: ExtendedNoteType, isVisible: boolean, isFullHeight: boolean, props: TypeWidgetProps }) {
|
||||||
const [ cachedProps, setCachedProps ] = useState(props);
|
const [ cachedProps, setCachedProps ] = useState(props);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -125,10 +126,15 @@ function NoteDetailWrapper({ Element, type, isVisible, props }: { Element: (prop
|
|||||||
}
|
}
|
||||||
}, [ isVisible ]);
|
}, [ isVisible ]);
|
||||||
|
|
||||||
|
const typeMapping = TYPE_MAPPINGS[type];
|
||||||
return (
|
return (
|
||||||
<div className={`note-detail-${type}`} style={{
|
<div
|
||||||
display: !isVisible ? "none" : ""
|
className={`${typeMapping.className} ${typeMapping.printable ? "note-detail-printable" : ""}`}
|
||||||
}}>
|
style={{
|
||||||
|
display: !isVisible ? "none" : "",
|
||||||
|
height: isFullHeight ? "100%" : ""
|
||||||
|
}}
|
||||||
|
>
|
||||||
{ <Element {...cachedProps} /> }
|
{ <Element {...cachedProps} /> }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -18,73 +18,117 @@ type NoteTypeView = () => Promise<{ default: TypeWidget } | TypeWidget> | ((prop
|
|||||||
|
|
||||||
interface NoteTypeMapping {
|
interface NoteTypeMapping {
|
||||||
view: NoteTypeView;
|
view: NoteTypeView;
|
||||||
|
printable?: boolean;
|
||||||
|
/** The class name to assign to the note type wrapper */
|
||||||
|
className: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TYPE_MAPPINGS: Record<ExtendedNoteType, NoteTypeMapping> = {
|
export const TYPE_MAPPINGS: Record<ExtendedNoteType, NoteTypeMapping> = {
|
||||||
empty: {
|
empty: {
|
||||||
view: () => import("./type_widgets/Empty"),
|
view: () => import("./type_widgets/Empty"),
|
||||||
|
className: "note-detail-empty",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
doc: {
|
doc: {
|
||||||
view: () => import("./type_widgets/Doc")
|
view: () => import("./type_widgets/Doc"),
|
||||||
|
className: "note-detail-doc",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
view: () => <div className="note-detail-none note-detail-printable" />
|
view: () => <></>,
|
||||||
|
className: "note-detail-none",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
protectedSession: {
|
protectedSession: {
|
||||||
view: () => import("./type_widgets/ProtectedSession")
|
view: () => import("./type_widgets/ProtectedSession"),
|
||||||
|
className: "protected-session-password-component"
|
||||||
},
|
},
|
||||||
book: {
|
book: {
|
||||||
view: () => import("./type_widgets/Book")
|
view: () => import("./type_widgets/Book"),
|
||||||
|
className: "note-detail-book",
|
||||||
|
printable: true,
|
||||||
},
|
},
|
||||||
contentWidget: {
|
contentWidget: {
|
||||||
view: () => import("./type_widgets/ContentWidget")
|
view: () => import("./type_widgets/ContentWidget"),
|
||||||
|
className: "note-detail-content-widget",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
webView: {
|
webView: {
|
||||||
view: () => import("./type_widgets/WebView")
|
view: () => import("./type_widgets/WebView"),
|
||||||
|
className: "note-detail-web-view",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
file: {
|
file: {
|
||||||
view: () => import("./type_widgets/File")
|
view: () => import("./type_widgets/File"),
|
||||||
|
className: "note-detail-file",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
image: {
|
image: {
|
||||||
view: () => import("./type_widgets/Image")
|
view: () => import("./type_widgets/Image"),
|
||||||
|
className: "note-detail-image",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
readOnlyCode: {
|
readOnlyCode: {
|
||||||
view: async () => (await import("./type_widgets/code/Code")).ReadOnlyCode
|
view: async () => (await import("./type_widgets/code/Code")).ReadOnlyCode,
|
||||||
|
className: "note-detail-readonly-code",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
editableCode: {
|
editableCode: {
|
||||||
view: async () => (await import("./type_widgets/code/Code")).EditableCode
|
view: async () => (await import("./type_widgets/code/Code")).EditableCode,
|
||||||
|
className: "note-detail-code",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
mermaid: {
|
mermaid: {
|
||||||
view: () => import("./type_widgets/Mermaid")
|
view: () => import("./type_widgets/Mermaid"),
|
||||||
|
className: "note-detail-mermaid",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
mindMap: {
|
mindMap: {
|
||||||
view: () => import("./type_widgets/MindMap")
|
view: () => import("./type_widgets/MindMap"),
|
||||||
|
className: "note-detail-mind-map",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
attachmentList: {
|
attachmentList: {
|
||||||
view: async () => (await import("./type_widgets/Attachment")).AttachmentList
|
view: async () => (await import("./type_widgets/Attachment")).AttachmentList,
|
||||||
|
className: "attachment-list",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
attachmentDetail: {
|
attachmentDetail: {
|
||||||
view: async () => (await import("./type_widgets/Attachment")).AttachmentDetail
|
view: async () => (await import("./type_widgets/Attachment")).AttachmentDetail,
|
||||||
|
className: "attachment-detail",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
readOnlyText: {
|
readOnlyText: {
|
||||||
view: () => import("./type_widgets/text/ReadOnlyText")
|
view: () => import("./type_widgets/text/ReadOnlyText"),
|
||||||
|
className: "note-detail-readonly-text"
|
||||||
},
|
},
|
||||||
editableText: {
|
editableText: {
|
||||||
view: () => import("./type_widgets/text/EditableText")
|
view: () => import("./type_widgets/text/EditableText"),
|
||||||
|
className: "note-detail-editable-text",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
render: {
|
render: {
|
||||||
view: () => import("./type_widgets/Render")
|
view: () => import("./type_widgets/Render"),
|
||||||
|
className: "note-detail-render",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
canvas: {
|
canvas: {
|
||||||
view: () => import("./type_widgets/Canvas")
|
view: () => import("./type_widgets/Canvas"),
|
||||||
|
className: "note-detail-canvas",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
relationMap: {
|
relationMap: {
|
||||||
view: () => import("./type_widgets/relation_map/RelationMap")
|
view: () => import("./type_widgets/relation_map/RelationMap"),
|
||||||
|
className: "note-detail-relation-map",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
noteMap: {
|
noteMap: {
|
||||||
view: () => import("./type_widgets/NoteMap")
|
view: () => import("./type_widgets/NoteMap"),
|
||||||
|
className: "note-detail-note-map",
|
||||||
|
printable: true
|
||||||
},
|
},
|
||||||
aiChat: {
|
aiChat: {
|
||||||
view: () => import("./type_widgets/AiChat")
|
view: () => import("./type_widgets/AiChat"),
|
||||||
|
className: "ai-chat-widget-container"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ export default function AiChat({ note, noteContext }: TypeWidgetProps) {
|
|||||||
return llmChatPanel;
|
return llmChatPanel;
|
||||||
}, {
|
}, {
|
||||||
noteContext,
|
noteContext,
|
||||||
containerClassName: "ai-chat-widget-container",
|
|
||||||
containerStyle: {
|
containerStyle: {
|
||||||
height: "100%"
|
height: "100%"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export function AttachmentList({ note }: TypeWidgetProps) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="attachment-list note-detail-printable">
|
<>
|
||||||
<AttachmentListHeader noteId={note.noteId} />
|
<AttachmentListHeader noteId={note.noteId} />
|
||||||
|
|
||||||
<div className="attachment-list-wrapper">
|
<div className="attachment-list-wrapper">
|
||||||
@@ -58,7 +58,7 @@ export function AttachmentList({ note }: TypeWidgetProps) {
|
|||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ export function AttachmentDetail({ note, viewScope }: TypeWidgetProps) {
|
|||||||
}, [ viewScope ]);
|
}, [ viewScope ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="attachment-detail note-detail-printable">
|
<>
|
||||||
<div className="links-wrapper use-tn-links">
|
<div className="links-wrapper use-tn-links">
|
||||||
{t("attachment_detail.owning_note")}{" "}
|
{t("attachment_detail.owning_note")}{" "}
|
||||||
<NoteLink notePath={note.noteId} />
|
<NoteLink notePath={note.noteId} />
|
||||||
@@ -122,7 +122,7 @@ export function AttachmentDetail({ note, viewScope }: TypeWidgetProps) {
|
|||||||
<strong>{t("attachment_detail.attachment_deleted")}</strong>
|
<strong>{t("attachment_detail.attachment_deleted")}</strong>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,13 +23,9 @@ export default function Book({ note }: TypeWidgetProps) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (shouldDisplayNoChildrenWarning &&
|
||||||
<div className="note-detail-book note-detail-printable">
|
|
||||||
{(shouldDisplayNoChildrenWarning && (
|
|
||||||
<Alert type="warning" className="note-detail-book-empty-help">
|
<Alert type="warning" className="note-detail-book-empty-help">
|
||||||
<RawHtml html={t("book.no_children_help")} />
|
<RawHtml html={t("book.no_children_help")} />
|
||||||
</Alert>
|
</Alert>
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,8 +60,7 @@ export default function Canvas({ note }: TypeWidgetProps) {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="canvas-widget note-detail-canvas note-detail-printable note-detail full-height" onWheel={onWheel}>
|
<div className="canvas-render" onWheel={onWheel}>
|
||||||
<div className="canvas-render">
|
|
||||||
<div className="excalidraw-wrapper">
|
<div className="excalidraw-wrapper">
|
||||||
<Excalidraw
|
<Excalidraw
|
||||||
excalidrawAPI={api => apiRef.current = api}
|
excalidrawAPI={api => apiRef.current = api}
|
||||||
@@ -83,7 +82,6 @@ export default function Canvas({ note }: TypeWidgetProps) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,12 +50,10 @@ const CONTENT_WIDGETS: Record<OptionPages | "_backendLog", (props: TypeWidgetPro
|
|||||||
export default function ContentWidget({ note, ...restProps }: TypeWidgetProps) {
|
export default function ContentWidget({ note, ...restProps }: TypeWidgetProps) {
|
||||||
const Content = CONTENT_WIDGETS[note.noteId];
|
const Content = CONTENT_WIDGETS[note.noteId];
|
||||||
return (
|
return (
|
||||||
<div className="note-detail-content-widget note-detail-printable">
|
|
||||||
<div className={`note-detail-content-widget-content ${note.noteId.startsWith("_options") ? "options" : ""}`}>
|
<div className={`note-detail-content-widget-content ${note.noteId.startsWith("_options") ? "options" : ""}`}>
|
||||||
{Content
|
{Content
|
||||||
? <Content note={note} {...restProps} />
|
? <Content note={note} {...restProps} />
|
||||||
: (t("content_widget.unknown_widget", { id: note.noteId }))}
|
: (t("content_widget.unknown_widget", { id: note.noteId }))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,15 +18,15 @@
|
|||||||
border: 1px solid var(--main-border-color);
|
border: 1px solid var(--main-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-detail-doc.contextual-help {
|
.note-detail-doc-content.contextual-help {
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-detail-doc.contextual-help h2,
|
.note-detail-doc-content.contextual-help h2,
|
||||||
.note-detail-doc.contextual-help h3,
|
.note-detail-doc-content.contextual-help h3,
|
||||||
.note-detail-doc.contextual-help h4,
|
.note-detail-doc-content.contextual-help h4,
|
||||||
.note-detail-doc.contextual-help h5,
|
.note-detail-doc-content.contextual-help h5,
|
||||||
.note-detail-doc.contextual-help h6 {
|
.note-detail-doc-content.contextual-help h6 {
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
background-color: var(--main-background-color);
|
background-color: var(--main-background-color);
|
||||||
position: sticky;
|
position: sticky;
|
||||||
|
|||||||
@@ -27,12 +27,10 @@ export default function Doc({ note, viewScope, ntxId }: TypeWidgetProps) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`note-detail-doc note-detail-printable ${viewScope?.viewMode === "contextual-help" ? "contextual-help" : ""}`}>
|
|
||||||
<RawHtmlBlock
|
<RawHtmlBlock
|
||||||
containerRef={containerRef}
|
containerRef={containerRef}
|
||||||
className="note-detail-doc-content ck-content"
|
className={`note-detail-doc-content ck-content ${viewScope?.viewMode === "contextual-help" ? "contextual-help" : ""}`}
|
||||||
html={html}
|
html={html}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ import { TypeWidgetProps } from "./type_widget";
|
|||||||
|
|
||||||
export default function Empty({ }: TypeWidgetProps) {
|
export default function Empty({ }: TypeWidgetProps) {
|
||||||
return (
|
return (
|
||||||
<div class="note-detail-empty note-detail-printable">
|
<>
|
||||||
<WorkspaceSwitcher />
|
<WorkspaceSwitcher />
|
||||||
<NoteSearch />
|
<NoteSearch />
|
||||||
</div>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,24 +12,17 @@ const TEXT_MAX_NUM_CHARS = 5000;
|
|||||||
export default function File({ note }: TypeWidgetProps) {
|
export default function File({ note }: TypeWidgetProps) {
|
||||||
const blob = useNoteBlob(note);
|
const blob = useNoteBlob(note);
|
||||||
|
|
||||||
let preview: VNode | null = null;
|
|
||||||
if (blob?.content) {
|
if (blob?.content) {
|
||||||
preview = <TextPreview content={blob.content} />
|
return <TextPreview content={blob.content} />
|
||||||
} else if (note.mime === "application/pdf") {
|
} else if (note.mime === "application/pdf") {
|
||||||
preview = <PdfPreview note={note} />
|
return <PdfPreview note={note} />
|
||||||
} else if (note.mime.startsWith("video/")) {
|
} else if (note.mime.startsWith("video/")) {
|
||||||
preview = <VideoPreview note={note} />
|
return <VideoPreview note={note} />
|
||||||
} else if (note.mime.startsWith("audio/")) {
|
} else if (note.mime.startsWith("audio/")) {
|
||||||
preview = <AudioPreview note={note} />
|
return <AudioPreview note={note} />
|
||||||
} else {
|
} else {
|
||||||
preview = <NoPreview />
|
return <NoPreview />
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="note-detail-file note-detail-printable">
|
|
||||||
{preview}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function TextPreview({ content }: { content: string }) {
|
function TextPreview({ content }: { content: string }) {
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ export default function Image({ note, ntxId }: TypeWidgetProps) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="note-detail-image note-detail-printable">
|
|
||||||
<div ref={containerRef} className="note-detail-image-wrapper">
|
<div ref={containerRef} className="note-detail-image-wrapper">
|
||||||
<img
|
<img
|
||||||
id={uniqueId}
|
id={uniqueId}
|
||||||
@@ -49,6 +48,5 @@ export default function Image({ note, ntxId }: TypeWidgetProps) {
|
|||||||
src={createImageSrcUrl(note)}
|
src={createImageSrcUrl(note)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import nodeMenu from "@mind-elixir/node-menu";
|
|||||||
import "mind-elixir/style";
|
import "mind-elixir/style";
|
||||||
import "@mind-elixir/node-menu/dist/style.css";
|
import "@mind-elixir/node-menu/dist/style.css";
|
||||||
import "./MindMap.css";
|
import "./MindMap.css";
|
||||||
import { useEditorSpacedUpdate, useNoteLabelBoolean, useTriliumEvent, useTriliumEvents, useTriliumOptionBool } from "../react/hooks";
|
import { useEditorSpacedUpdate, useNoteLabelBoolean, useSyncedRef, useTriliumEvent, useTriliumEvents, useTriliumOptionBool } from "../react/hooks";
|
||||||
import { refToJQuerySelector } from "../react/react_utils";
|
import { refToJQuerySelector } from "../react/react_utils";
|
||||||
import utils from "../../services/utils";
|
import utils from "../../services/utils";
|
||||||
|
|
||||||
@@ -16,6 +16,7 @@ const NEW_TOPIC_NAME = "";
|
|||||||
interface MindElixirProps {
|
interface MindElixirProps {
|
||||||
apiRef?: RefObject<MindElixirInstance>;
|
apiRef?: RefObject<MindElixirInstance>;
|
||||||
containerProps?: Omit<HTMLAttributes<HTMLDivElement>, "ref">;
|
containerProps?: Omit<HTMLAttributes<HTMLDivElement>, "ref">;
|
||||||
|
containerRef?: RefObject<HTMLDivElement>;
|
||||||
editable: boolean;
|
editable: boolean;
|
||||||
content: MindElixirData;
|
content: MindElixirData;
|
||||||
onChange?: () => void;
|
onChange?: () => void;
|
||||||
@@ -94,8 +95,8 @@ export default function MindMap({ note, ntxId }: TypeWidgetProps) {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={containerRef} className="note-detail-mind-map note-detail-printable">
|
|
||||||
<MindElixir
|
<MindElixir
|
||||||
|
containerRef={containerRef}
|
||||||
apiRef={apiRef}
|
apiRef={apiRef}
|
||||||
content={content}
|
content={content}
|
||||||
onChange={() => spacedUpdate.scheduleUpdate()}
|
onChange={() => spacedUpdate.scheduleUpdate()}
|
||||||
@@ -105,12 +106,11 @@ export default function MindMap({ note, ntxId }: TypeWidgetProps) {
|
|||||||
onKeyDown
|
onKeyDown
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function MindElixir({ content, containerProps, apiRef: externalApiRef, onChange, editable }: MindElixirProps) {
|
function MindElixir({ content, containerRef: externalContainerRef, containerProps, apiRef: externalApiRef, onChange, editable }: MindElixirProps) {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useSyncedRef<HTMLDivElement>(externalContainerRef, null);
|
||||||
const apiRef = useRef<MindElixirInstance>(null);
|
const apiRef = useRef<MindElixirInstance>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export default function NoteMap({ note }: TypeWidgetProps) {
|
|||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={containerRef} className="note-detail-note-map note-detail-printable">
|
<div ref={containerRef}>
|
||||||
<NoteMapEl parentRef={containerRef} note={note} widgetMode="type" />
|
<NoteMapEl parentRef={containerRef} note={note} widgetMode="type" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ export default function ProtectedSession() {
|
|||||||
}, [ passwordRef ]);
|
}, [ passwordRef ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="protected-session-password-component note-detail-printable">
|
|
||||||
<form class="protected-session-password-form" onSubmit={submitCallback}>
|
<form class="protected-session-password-form" onSubmit={submitCallback}>
|
||||||
<FormGroup name="protected-session-password-in-detail" label={t("protected_session.enter_password_instruction")}>
|
<FormGroup name="protected-session-password-in-detail" label={t("protected_session.enter_password_instruction")}>
|
||||||
<FormTextBox
|
<FormTextBox
|
||||||
@@ -37,6 +36,5 @@ export default function ProtectedSession() {
|
|||||||
keyboardShortcut="Enter"
|
keyboardShortcut="Enter"
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export default function Render({ note, noteContext, ntxId }: TypeWidgetProps) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="note-detail-render note-detail-printable">
|
<>
|
||||||
{!renderNotesFound && (
|
{!renderNotesFound && (
|
||||||
<Alert className="note-detail-render-help" type="warning">
|
<Alert className="note-detail-render-help" type="warning">
|
||||||
<p><strong>{t("render.note_detail_render_help_1")}</strong></p>
|
<p><strong>{t("render.note_detail_render_help_1")}</strong></p>
|
||||||
@@ -47,6 +47,6 @@ export default function Render({ note, noteContext, ntxId }: TypeWidgetProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div ref={contentRef} className="note-detail-render-content" />
|
<div ref={contentRef} className="note-detail-render-content" />
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,10 @@ const isElectron = utils.isElectron();
|
|||||||
export default function WebView({ note }: TypeWidgetProps) {
|
export default function WebView({ note }: TypeWidgetProps) {
|
||||||
const [ webViewSrc ] = useNoteLabel(note, "webViewSrc");
|
const [ webViewSrc ] = useNoteLabel(note, "webViewSrc");
|
||||||
|
|
||||||
return (
|
return (webViewSrc
|
||||||
<div className="note-detail-web-view note-detail-printable">
|
|
||||||
{webViewSrc
|
|
||||||
? <WebViewContent src={webViewSrc} />
|
? <WebViewContent src={webViewSrc} />
|
||||||
: <WebViewHelp />}
|
: <WebViewHelp />
|
||||||
</div>
|
);
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function WebViewContent({ src }: { src: string }) {
|
function WebViewContent({ src }: { src: string }) {
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ export function ReadOnlyCode({ note, viewScope, ntxId, parentComponent }: TypeWi
|
|||||||
}, [ blob ]);
|
}, [ blob ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="note-detail-readonly-code note-detail-printable">
|
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
ntxId={ntxId} parentComponent={parentComponent}
|
ntxId={ntxId} parentComponent={parentComponent}
|
||||||
className="note-detail-readonly-code-content"
|
className="note-detail-readonly-code-content"
|
||||||
@@ -52,7 +51,6 @@ export function ReadOnlyCode({ note, viewScope, ntxId, parentComponent }: TypeWi
|
|||||||
mime={note.mime}
|
mime={note.mime}
|
||||||
readOnly
|
readOnly
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +91,7 @@ export function EditableCode({ note, ntxId, debounceUpdate, parentComponent, upd
|
|||||||
useKeyboardShortcuts("code-detail", containerRef, parentComponent);
|
useKeyboardShortcuts("code-detail", containerRef, parentComponent);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="note-detail-code note-detail-printable">
|
<>
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
ntxId={ntxId} parentComponent={parentComponent}
|
ntxId={ntxId} parentComponent={parentComponent}
|
||||||
editorRef={editorRef} containerRef={containerRef}
|
editorRef={editorRef} containerRef={containerRef}
|
||||||
@@ -119,7 +117,7 @@ export function EditableCode({ note, ntxId, debounceUpdate, parentComponent, upd
|
|||||||
<TouchBarButton icon="NSImageNameTouchBarPlayTemplate" click={() => appContext.triggerCommand("runActiveNote")} />
|
<TouchBarButton icon="NSImageNameTouchBarPlayTemplate" click={() => appContext.triggerCommand("runActiveNote")} />
|
||||||
)}
|
)}
|
||||||
</TouchBar>
|
</TouchBar>
|
||||||
</div>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,6 @@ export default function RelationMap({ note, ntxId }: TypeWidgetProps) {
|
|||||||
useRelationData(note.noteId, data, mapApiRef, pbApiRef);
|
useRelationData(note.noteId, data, mapApiRef, pbApiRef);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="note-detail-relation-map note-detail-printable">
|
|
||||||
<div
|
<div
|
||||||
className="relation-map-wrapper"
|
className="relation-map-wrapper"
|
||||||
onClick={clickCallback}
|
onClick={clickCallback}
|
||||||
@@ -157,7 +156,6 @@ export default function RelationMap({ note, ntxId }: TypeWidgetProps) {
|
|||||||
))}
|
))}
|
||||||
</JsPlumb>
|
</JsPlumb>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { HTMLProps, RefObject, useEffect, useImperativeHandle, useRef, useState } from "preact/compat";
|
import { HTMLProps, RefObject, useEffect, useImperativeHandle, useRef, useState } from "preact/compat";
|
||||||
import { PopupEditor, ClassicEditor, EditorWatchdog, type WatchdogConfig, CKTextEditor, TemplateDefinition } from "@triliumnext/ckeditor5";
|
import { PopupEditor, ClassicEditor, EditorWatchdog, type WatchdogConfig, CKTextEditor, TemplateDefinition } from "@triliumnext/ckeditor5";
|
||||||
import { buildConfig, BuildEditorOptions } from "./config";
|
import { buildConfig, BuildEditorOptions } from "./config";
|
||||||
import { useLegacyImperativeHandlers } from "../../react/hooks";
|
import { useLegacyImperativeHandlers, useSyncedRef } from "../../react/hooks";
|
||||||
import link from "../../../services/link";
|
import link from "../../../services/link";
|
||||||
import froca from "../../../services/froca";
|
import froca from "../../../services/froca";
|
||||||
|
|
||||||
@@ -30,10 +30,11 @@ interface CKEditorWithWatchdogProps extends Pick<HTMLProps<HTMLDivElement>, "cla
|
|||||||
onEditorInitialized?: (editor: CKTextEditor) => void;
|
onEditorInitialized?: (editor: CKTextEditor) => void;
|
||||||
editorApi: RefObject<CKEditorApi>;
|
editorApi: RefObject<CKEditorApi>;
|
||||||
templates: TemplateDefinition[];
|
templates: TemplateDefinition[];
|
||||||
|
containerRef?: RefObject<HTMLDivElement>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CKEditorWithWatchdog({ content, contentLanguage, className, tabIndex, isClassicEditor, watchdogRef: externalWatchdogRef, watchdogConfig, onNotificationWarning, onWatchdogStateChange, onChange, onEditorInitialized, editorApi, templates }: CKEditorWithWatchdogProps) {
|
export default function CKEditorWithWatchdog({ containerRef: externalContainerRef, content, contentLanguage, className, tabIndex, isClassicEditor, watchdogRef: externalWatchdogRef, watchdogConfig, onNotificationWarning, onWatchdogStateChange, onChange, onEditorInitialized, editorApi, templates }: CKEditorWithWatchdogProps) {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useSyncedRef<HTMLDivElement>(externalContainerRef, null);
|
||||||
const watchdogRef = useRef<EditorWatchdog>(null);
|
const watchdogRef = useRef<EditorWatchdog>(null);
|
||||||
const [ editor, setEditor ] = useState<CKTextEditor>();
|
const [ editor, setEditor ] = useState<CKTextEditor>();
|
||||||
|
|
||||||
|
|||||||
@@ -185,9 +185,10 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={containerRef} class={`note-detail-editable-text note-detail-printable ${codeBlockWordWrap ? "word-wrap" : ""}`}>
|
<>
|
||||||
{note && !!templates && <CKEditorWithWatchdog
|
{note && !!templates && <CKEditorWithWatchdog
|
||||||
className="note-detail-editable-text-editor use-tn-links"
|
containerRef={containerRef}
|
||||||
|
className={`note-detail-editable-text-editor use-tn-links ${codeBlockWordWrap ? "word-wrap" : ""}`}
|
||||||
tabIndex={300}
|
tabIndex={300}
|
||||||
content={content}
|
content={content}
|
||||||
contentLanguage={language}
|
contentLanguage={language}
|
||||||
@@ -229,7 +230,7 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext
|
|||||||
/>}
|
/>}
|
||||||
|
|
||||||
<EditableTextTouchBar watchdogRef={watchdogRef} refreshTouchBarRef={refreshTouchBarRef} />
|
<EditableTextTouchBar watchdogRef={watchdogRef} refreshTouchBarRef={refreshTouchBarRef} />
|
||||||
</div>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user