mirror of
https://github.com/zadam/trilium.git
synced 2025-11-10 15:25:51 +01:00
chore(react/type_widgets): start porting canvas
This commit is contained in:
@@ -33,7 +33,8 @@ const TYPE_MAPPINGS: Record<ExtendedNoteType, () => Promise<{ default: TypeWidge
|
|||||||
"attachmentList": async () => (await import("./type_widgets/Attachment")).AttachmentList,
|
"attachmentList": async () => (await import("./type_widgets/Attachment")).AttachmentList,
|
||||||
"attachmentDetail": async () => (await import("./type_widgets/Attachment")).AttachmentDetail,
|
"attachmentDetail": async () => (await import("./type_widgets/Attachment")).AttachmentDetail,
|
||||||
"readOnlyText": () => import("./type_widgets/text/ReadOnlyText"),
|
"readOnlyText": () => import("./type_widgets/text/ReadOnlyText"),
|
||||||
"render": () => import("./type_widgets/Render")
|
"render": () => import("./type_widgets/Render"),
|
||||||
|
"canvas": () => import("./type_widgets/Canvas")
|
||||||
// TODO: finalize the record.
|
// TODO: finalize the record.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
34
apps/client/src/widgets/type_widgets/Canvas.css
Normal file
34
apps/client/src/widgets/type_widgets/Canvas.css
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
.excalidraw .App-menu_top .buttonList {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Conflict between excalidraw and bootstrap classes keeps the menu hidden */
|
||||||
|
/* https://github.com/zadam/trilium/issues/3780 */
|
||||||
|
/* https://github.com/excalidraw/excalidraw/issues/6567 */
|
||||||
|
.excalidraw .dropdown-menu {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.excalidraw-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[dir="ltr"]
|
||||||
|
.excalidraw
|
||||||
|
.layer-ui__wrapper
|
||||||
|
.zen-mode-transition.App-menu_bottom--transition-left {
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* collaboration not possible so hide the button */
|
||||||
|
.CollabButton {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.library-button {
|
||||||
|
display: none !important; /* library won't work without extra support which isn't currently implemented */
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-detail-canvas > .canvas-render {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
41
apps/client/src/widgets/type_widgets/Canvas.tsx
Normal file
41
apps/client/src/widgets/type_widgets/Canvas.tsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { Excalidraw } from "@excalidraw/excalidraw";
|
||||||
|
import { TypeWidgetProps } from "./type_widget";
|
||||||
|
import "@excalidraw/excalidraw/index.css";
|
||||||
|
import { useNoteBlob } from "../react/hooks";
|
||||||
|
import { useEffect, useRef } from "preact/hooks";
|
||||||
|
import type { ExcalidrawImperativeAPI, Theme } from "@excalidraw/excalidraw/types";
|
||||||
|
import "./Canvas.css";
|
||||||
|
|
||||||
|
export default function Canvas({ note }: TypeWidgetProps) {
|
||||||
|
const apiRef = useRef<ExcalidrawImperativeAPI>(null);
|
||||||
|
const blob = useNoteBlob(note);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const documentStyle = window.getComputedStyle(document.documentElement);
|
||||||
|
const themeStyle = documentStyle.getPropertyValue("--theme-style")?.trim() as Theme;
|
||||||
|
|
||||||
|
const api = apiRef.current;
|
||||||
|
const content = blob?.content;
|
||||||
|
if (!api) return;
|
||||||
|
if (!content?.trim()) {
|
||||||
|
api.updateScene({
|
||||||
|
elements: [],
|
||||||
|
appState: {
|
||||||
|
theme: themeStyle
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [ blob ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="canvas-widget note-detail-canvas note-detail-printable note-detail full-height">
|
||||||
|
<div className="canvas-render">
|
||||||
|
<div className="excalidraw-wrapper">
|
||||||
|
<Excalidraw
|
||||||
|
excalidrawAPI={api => apiRef.current = api}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -3,55 +3,12 @@ import server from "../../services/server.js";
|
|||||||
import type FNote from "../../entities/fnote.js";
|
import type FNote from "../../entities/fnote.js";
|
||||||
import options from "../../services/options.js";
|
import options from "../../services/options.js";
|
||||||
import type { LibraryItem } from "@excalidraw/excalidraw/types";
|
import type { LibraryItem } from "@excalidraw/excalidraw/types";
|
||||||
import type { Theme } from "@excalidraw/excalidraw/element/types";
|
|
||||||
import type Canvas from "./canvas_el.js";
|
import type Canvas from "./canvas_el.js";
|
||||||
import { CanvasContent } from "./canvas_el.js";
|
import { CanvasContent } from "./canvas_el.js";
|
||||||
import { renderReactWidget } from "../react/react_utils.jsx";
|
import { renderReactWidget } from "../react/react_utils.jsx";
|
||||||
import SpacedUpdate from "../../services/spaced_update.js";
|
import SpacedUpdate from "../../services/spaced_update.js";
|
||||||
import protected_session_holder from "../../services/protected_session_holder.js";
|
import protected_session_holder from "../../services/protected_session_holder.js";
|
||||||
|
|
||||||
const TPL = /*html*/`
|
|
||||||
<div class="canvas-widget note-detail-canvas note-detail-printable note-detail">
|
|
||||||
<style>
|
|
||||||
.excalidraw .App-menu_top .buttonList {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Conflict between excalidraw and bootstrap classes keeps the menu hidden */
|
|
||||||
/* https://github.com/zadam/trilium/issues/3780 */
|
|
||||||
/* https://github.com/excalidraw/excalidraw/issues/6567 */
|
|
||||||
.excalidraw .dropdown-menu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.excalidraw-wrapper {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root[dir="ltr"]
|
|
||||||
.excalidraw
|
|
||||||
.layer-ui__wrapper
|
|
||||||
.zen-mode-transition.App-menu_bottom--transition-left {
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* collaboration not possible so hide the button */
|
|
||||||
.CollabButton {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.library-button {
|
|
||||||
display: none !important; /* library won't work without extra support which isn't currently implemented */
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
<!-- height here necessary. otherwise excalidraw not shown -->
|
|
||||||
<div class="canvas-render" style="height: 100%"></div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface AttachmentMetadata {
|
interface AttachmentMetadata {
|
||||||
title: string;
|
title: string;
|
||||||
attachmentId: string;
|
attachmentId: string;
|
||||||
@@ -151,10 +108,6 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static getType() {
|
|
||||||
return "canvas";
|
|
||||||
}
|
|
||||||
|
|
||||||
doRender() {
|
doRender() {
|
||||||
this.$widget = $(TPL);
|
this.$widget = $(TPL);
|
||||||
this.$widget.bind("mousewheel DOMMouseScroll", (event) => {
|
this.$widget.bind("mousewheel DOMMouseScroll", (event) => {
|
||||||
@@ -165,10 +118,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$widget.toggleClass("full-height", true);
|
|
||||||
this.$render = this.$widget.find(".canvas-render");
|
this.$render = this.$widget.find(".canvas-render");
|
||||||
const documentStyle = window.getComputedStyle(document.documentElement);
|
|
||||||
this.themeStyle = documentStyle.getPropertyValue("--theme-style")?.trim() as Theme;
|
|
||||||
|
|
||||||
this.#init();
|
this.#init();
|
||||||
|
|
||||||
@@ -229,9 +179,6 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
// get note from backend and put into canvas
|
// get note from backend and put into canvas
|
||||||
const blob = await note.getBlob();
|
const blob = await note.getBlob();
|
||||||
|
|
||||||
// before we load content into excalidraw, make sure excalidraw has loaded
|
|
||||||
await this.canvasInstance.waitForApiToBecomeAvailable();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* new and empty note - make sure that canvas is empty.
|
* new and empty note - make sure that canvas is empty.
|
||||||
* If we do not set it manually, we occasionally get some "bleeding" from another
|
* If we do not set it manually, we occasionally get some "bleeding" from another
|
||||||
@@ -239,7 +186,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
* newly instantiated?
|
* newly instantiated?
|
||||||
*/
|
*/
|
||||||
if (!blob?.content?.trim()) {
|
if (!blob?.content?.trim()) {
|
||||||
this.canvasInstance.resetScene(this.themeStyle);
|
|
||||||
} else if (blob.content) {
|
} else if (blob.content) {
|
||||||
let content: CanvasContent;
|
let content: CanvasContent;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import "@excalidraw/excalidraw/index.css";
|
|
||||||
import { Excalidraw, getSceneVersion, exportToSvg } from "@excalidraw/excalidraw";
|
import { Excalidraw, getSceneVersion, exportToSvg } from "@excalidraw/excalidraw";
|
||||||
import { AppState, BinaryFileData, ExcalidrawImperativeAPI, ExcalidrawProps, LibraryItem } from "@excalidraw/excalidraw/types";
|
import { AppState, BinaryFileData, ExcalidrawImperativeAPI, ExcalidrawProps, LibraryItem } from "@excalidraw/excalidraw/types";
|
||||||
import { ExcalidrawElement, NonDeletedExcalidrawElement, Theme } from "@excalidraw/excalidraw/element/types";
|
import { ExcalidrawElement, NonDeletedExcalidrawElement, Theme } from "@excalidraw/excalidraw/element/types";
|
||||||
@@ -19,7 +18,6 @@ export default class Canvas {
|
|||||||
private currentSceneVersion: number;
|
private currentSceneVersion: number;
|
||||||
private opts: ExcalidrawProps;
|
private opts: ExcalidrawProps;
|
||||||
private excalidrawApi!: ExcalidrawImperativeAPI;
|
private excalidrawApi!: ExcalidrawImperativeAPI;
|
||||||
private initializedPromise: JQuery.Deferred<void>;
|
|
||||||
|
|
||||||
constructor(opts: ExcalidrawProps) {
|
constructor(opts: ExcalidrawProps) {
|
||||||
this.opts = opts;
|
this.opts = opts;
|
||||||
@@ -27,19 +25,9 @@ export default class Canvas {
|
|||||||
this.initializedPromise = $.Deferred();
|
this.initializedPromise = $.Deferred();
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForApiToBecomeAvailable() {
|
|
||||||
while (!this.excalidrawApi) {
|
|
||||||
await this.initializedPromise;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createCanvasElement() {
|
createCanvasElement() {
|
||||||
return <CanvasElement
|
return <CanvasElement
|
||||||
{...this.opts}
|
{...this.opts}
|
||||||
excalidrawAPI={api => {
|
|
||||||
this.excalidrawApi = api;
|
|
||||||
this.initializedPromise.resolve();
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,15 +68,6 @@ export default class Canvas {
|
|||||||
return !!this.excalidrawApi;
|
return !!this.excalidrawApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
resetScene(theme: Theme) {
|
|
||||||
this.excalidrawApi.updateScene({
|
|
||||||
elements: [],
|
|
||||||
appState: {
|
|
||||||
theme
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
loadData(content: CanvasContent, theme: Theme) {
|
loadData(content: CanvasContent, theme: Theme) {
|
||||||
const { elements, files } = content;
|
const { elements, files } = content;
|
||||||
const appState: Partial<AppState> = content.appState ?? {};
|
const appState: Partial<AppState> = content.appState ?? {};
|
||||||
@@ -178,7 +157,6 @@ export default class Canvas {
|
|||||||
|
|
||||||
function CanvasElement(opts: ExcalidrawProps) {
|
function CanvasElement(opts: ExcalidrawProps) {
|
||||||
return (
|
return (
|
||||||
<div className="excalidraw-wrapper">
|
|
||||||
<Excalidraw
|
<Excalidraw
|
||||||
{...opts}
|
{...opts}
|
||||||
onLinkOpen={useCallback((element: NonDeletedExcalidrawElement, event: CustomEvent) => {
|
onLinkOpen={useCallback((element: NonDeletedExcalidrawElement, event: CustomEvent) => {
|
||||||
@@ -196,6 +174,5 @@ function CanvasElement(opts: ExcalidrawProps) {
|
|||||||
return linkService.goToLinkExt(nativeEvent, link, null);
|
return linkService.goToLinkExt(nativeEvent, link, null);
|
||||||
}, [])}
|
}, [])}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user