mirror of
https://github.com/zadam/trilium.git
synced 2025-10-20 15:19:01 +02:00
feat(react/ribbon): display help tooltip in attribute editor
This commit is contained in:
parent
1e00407864
commit
befc5a9530
@ -16,12 +16,7 @@ import type { default as FAttribute, AttributeType } from "../../entities/fattri
|
|||||||
import type FNote from "../../entities/fnote.js";
|
import type FNote from "../../entities/fnote.js";
|
||||||
import { escapeQuotes } from "../../services/utils.js";
|
import { escapeQuotes } from "../../services/utils.js";
|
||||||
|
|
||||||
const HELP_TEXT = `
|
|
||||||
<p>${t("attribute_editor.help_text_body1")}</p>
|
|
||||||
|
|
||||||
<p>${t("attribute_editor.help_text_body2")}</p>
|
|
||||||
|
|
||||||
<p>${t("attribute_editor.help_text_body3")}</p>`;
|
|
||||||
|
|
||||||
const TPL = /*html*/`
|
const TPL = /*html*/`
|
||||||
|
|
||||||
@ -229,9 +224,7 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget implem
|
|||||||
}
|
}
|
||||||
|
|
||||||
async handleEditorClick(e: JQuery.ClickEvent) {
|
async handleEditorClick(e: JQuery.ClickEvent) {
|
||||||
const pos = this.textEditor.model.document.selection.getFirstPosition();
|
if () {
|
||||||
|
|
||||||
if (pos && pos.textNode && pos.textNode.data) {
|
|
||||||
const clickIndex = this.getClickIndex(pos);
|
const clickIndex = this.getClickIndex(pos);
|
||||||
|
|
||||||
let parsedAttrs;
|
let parsedAttrs;
|
||||||
@ -267,25 +260,9 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget implem
|
|||||||
this.showHelpTooltip();
|
this.showHelpTooltip();
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
} else {
|
|
||||||
this.showHelpTooltip();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showHelpTooltip() {
|
|
||||||
this.attributeDetailWidget.hide();
|
|
||||||
|
|
||||||
this.$editor.tooltip({
|
|
||||||
trigger: "focus",
|
|
||||||
html: true,
|
|
||||||
title: HELP_TEXT,
|
|
||||||
placement: "bottom",
|
|
||||||
offset: "0,30"
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$editor.tooltip("show");
|
|
||||||
}
|
|
||||||
|
|
||||||
getClickIndex(pos: ModelPosition) {
|
getClickIndex(pos: ModelPosition) {
|
||||||
let clickIndex = pos.offset - (pos.textNode?.startOffset ?? 0);
|
let clickIndex = pos.offset - (pos.textNode?.startOffset ?? 0);
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { AttributeEditor, EditorConfig } from "@triliumnext/ckeditor5";
|
import { CKTextEditor, type AttributeEditor, type EditorConfig, type ModelPosition } from "@triliumnext/ckeditor5";
|
||||||
import { useEffect, useRef } from "preact/compat";
|
import { useEffect, useRef } from "preact/compat";
|
||||||
|
|
||||||
interface CKEditorOpts {
|
interface CKEditorOpts {
|
||||||
@ -9,15 +9,19 @@ interface CKEditorOpts {
|
|||||||
disableNewlines?: boolean;
|
disableNewlines?: boolean;
|
||||||
disableSpellcheck?: boolean;
|
disableSpellcheck?: boolean;
|
||||||
onChange?: () => void;
|
onChange?: () => void;
|
||||||
|
onClick?: (pos?: ModelPosition | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CKEditor({ className, tabIndex, editor, config, disableNewlines, disableSpellcheck, onChange }: CKEditorOpts) {
|
export default function CKEditor({ className, tabIndex, editor, config, disableNewlines, disableSpellcheck, onChange, onClick }: CKEditorOpts) {
|
||||||
const editorContainerRef = useRef<HTMLDivElement>(null);
|
const editorContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const textEditorRef = useRef<CKTextEditor>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!editorContainerRef.current) return;
|
if (!editorContainerRef.current) return;
|
||||||
|
|
||||||
editor.create(editorContainerRef.current, config).then((textEditor) => {
|
editor.create(editorContainerRef.current, config).then((textEditor) => {
|
||||||
|
textEditorRef.current = textEditor;
|
||||||
|
|
||||||
if (disableNewlines) {
|
if (disableNewlines) {
|
||||||
textEditor.editing.view.document.on(
|
textEditor.editing.view.document.on(
|
||||||
"enter",
|
"enter",
|
||||||
@ -48,6 +52,12 @@ export default function CKEditor({ className, tabIndex, editor, config, disableN
|
|||||||
ref={editorContainerRef}
|
ref={editorContainerRef}
|
||||||
className={className}
|
className={className}
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
|
onClick={() => {
|
||||||
|
if (onClick) {
|
||||||
|
const pos = textEditorRef.current?.model.document.selection.getFirstPosition();
|
||||||
|
onClick(pos);
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -12,7 +12,8 @@ import FNote from "../../entities/fnote";
|
|||||||
import attributes from "../../services/attributes";
|
import attributes from "../../services/attributes";
|
||||||
import FBlob from "../../entities/fblob";
|
import FBlob from "../../entities/fblob";
|
||||||
import NoteContextAwareWidget from "../note_context_aware_widget";
|
import NoteContextAwareWidget from "../note_context_aware_widget";
|
||||||
import { RefObject, VNode } from "preact";
|
import { Ref, RefObject, VNode } from "preact";
|
||||||
|
import { Tooltip } from "bootstrap";
|
||||||
|
|
||||||
type TriliumEventHandler<T extends EventNames> = (data: EventData<T>) => void;
|
type TriliumEventHandler<T extends EventNames> = (data: EventData<T>) => void;
|
||||||
const registeredHandlers: Map<Component, Map<EventNames, TriliumEventHandler<any>[]>> = new Map();
|
const registeredHandlers: Map<Component, Map<EventNames, TriliumEventHandler<any>[]>> = new Map();
|
||||||
@ -510,4 +511,29 @@ export function useWindowSize() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTooltip(elRef: RefObject<HTMLElement>, config: Partial<Tooltip.Options>) {
|
||||||
|
useEffect(() => {
|
||||||
|
if (!elRef?.current) return;
|
||||||
|
|
||||||
|
const $el = $(elRef.current);
|
||||||
|
$el.tooltip(config);
|
||||||
|
}, [ elRef, config ]);
|
||||||
|
|
||||||
|
const showTooltip = useCallback(() => {
|
||||||
|
if (!elRef?.current) return;
|
||||||
|
|
||||||
|
const $el = $(elRef.current);
|
||||||
|
$el.tooltip("show");
|
||||||
|
}, [ elRef ]);
|
||||||
|
|
||||||
|
const hideTooltip = useCallback(() => {
|
||||||
|
if (!elRef?.current) return;
|
||||||
|
|
||||||
|
const $el = $(elRef.current);
|
||||||
|
$el.tooltip("hide");
|
||||||
|
}, [ elRef ]);
|
||||||
|
|
||||||
|
return { showTooltip, hideTooltip };
|
||||||
}
|
}
|
@ -1,9 +1,17 @@
|
|||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks"
|
import { useEffect, useRef, useState } from "preact/hooks"
|
||||||
import { AttributeEditor as CKEditorAttributeEditor, EditorConfig, MentionFeed } from "@triliumnext/ckeditor5";
|
import { AttributeEditor as CKEditorAttributeEditor, MentionFeed } from "@triliumnext/ckeditor5";
|
||||||
import { t } from "../../../services/i18n";
|
import { t } from "../../../services/i18n";
|
||||||
import server from "../../../services/server";
|
import server from "../../../services/server";
|
||||||
import note_autocomplete, { Suggestion } from "../../../services/note_autocomplete";
|
import note_autocomplete, { Suggestion } from "../../../services/note_autocomplete";
|
||||||
import CKEditor from "../../react/CKEditor";
|
import CKEditor from "../../react/CKEditor";
|
||||||
|
import { useTooltip } from "../../react/hooks";
|
||||||
|
|
||||||
|
const HELP_TEXT = `
|
||||||
|
<p>${t("attribute_editor.help_text_body1")}</p>
|
||||||
|
|
||||||
|
<p>${t("attribute_editor.help_text_body2")}</p>
|
||||||
|
|
||||||
|
<p>${t("attribute_editor.help_text_body3")}</p>`;
|
||||||
|
|
||||||
const mentionSetup: MentionFeed[] = [
|
const mentionSetup: MentionFeed[] = [
|
||||||
{
|
{
|
||||||
@ -51,11 +59,27 @@ const mentionSetup: MentionFeed[] = [
|
|||||||
|
|
||||||
|
|
||||||
export default function AttributeEditor() {
|
export default function AttributeEditor() {
|
||||||
|
|
||||||
const [ attributeDetailVisible, setAttributeDetailVisible ] = useState(false);
|
|
||||||
|
|
||||||
|
const [ state, setState ] = useState<"normal" | "showHelpTooltip" | "showAttributeDetail">();
|
||||||
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||||
|
const { showTooltip, hideTooltip } = useTooltip(wrapperRef, {
|
||||||
|
trigger: "focus",
|
||||||
|
html: true,
|
||||||
|
title: HELP_TEXT,
|
||||||
|
placement: "bottom",
|
||||||
|
offset: "0,30"
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (state === "showHelpTooltip") {
|
||||||
|
showTooltip();
|
||||||
|
} else {
|
||||||
|
hideTooltip();
|
||||||
|
}
|
||||||
|
}, [ state ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style="position: relative; padding-top: 10px; padding-bottom: 10px">
|
<div ref={wrapperRef} style="position: relative; padding-top: 10px; padding-bottom: 10px">
|
||||||
<CKEditor
|
<CKEditor
|
||||||
className="attribute-list-editor"
|
className="attribute-list-editor"
|
||||||
tabIndex={200}
|
tabIndex={200}
|
||||||
@ -69,6 +93,13 @@ export default function AttributeEditor() {
|
|||||||
onChange={() => {
|
onChange={() => {
|
||||||
console.log("Data changed!");
|
console.log("Data changed!");
|
||||||
}}
|
}}
|
||||||
|
onClick={(pos) => {
|
||||||
|
if (pos && pos.textNode && pos.textNode.data) {
|
||||||
|
setState("showAttributeDetail")
|
||||||
|
} else {
|
||||||
|
setState("showHelpTooltip");
|
||||||
|
}
|
||||||
|
}}
|
||||||
disableNewlines disableSpellcheck
|
disableNewlines disableSpellcheck
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user