mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	feat(react/floating_buttons): port in-app help button
This commit is contained in:
		| @@ -1,5 +1,5 @@ | ||||
| import { describe, expect, it } from "vitest"; | ||||
| import { byBookType, byNoteType } from "./help_button.js"; | ||||
| import { byBookType, byNoteType } from "./in_app_help.js"; | ||||
| import fs from "fs"; | ||||
| import type { HiddenSubtreeItem } from "@triliumnext/commons"; | ||||
| import path from "path"; | ||||
| @@ -25,7 +25,7 @@ describe("Help button", () => { | ||||
|             ...Object.values(byBookType) | ||||
|         ].filter((noteId) => noteId) as string[]; | ||||
| 
 | ||||
|         const metaPath = path.resolve(path.join(__dirname, "../../../../server/src/assets/doc_notes/en/User Guide/!!!meta.json")); | ||||
|         const metaPath = path.resolve(path.join(__dirname, "../../../server/src/assets/doc_notes/en/User Guide/!!!meta.json")); | ||||
|         const meta: HiddenSubtreeItem[] = JSON.parse(fs.readFileSync(metaPath, "utf-8")); | ||||
|         const allNoteIds = new Set(getNoteIds(meta)); | ||||
| 
 | ||||
							
								
								
									
										43
									
								
								apps/client/src/services/in_app_help.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								apps/client/src/services/in_app_help.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| import { NoteType } from "@triliumnext/commons"; | ||||
| import { ViewTypeOptions } from "./note_list_renderer"; | ||||
| import { FNote } from "./frontend_script_entrypoint"; | ||||
|  | ||||
| export const byNoteType: Record<Exclude<NoteType, "book">, string | null> = { | ||||
|     canvas: null, | ||||
|     code: null, | ||||
|     contentWidget: null, | ||||
|     doc: null, | ||||
|     file: null, | ||||
|     image: null, | ||||
|     launcher: null, | ||||
|     mermaid: null, | ||||
|     mindMap: null, | ||||
|     noteMap: null, | ||||
|     relationMap: null, | ||||
|     render: null, | ||||
|     search: null, | ||||
|     text: null, | ||||
|     webView: null, | ||||
|     aiChat: null | ||||
| }; | ||||
|  | ||||
| export const byBookType: Record<ViewTypeOptions, string | null> = { | ||||
|     list: "mULW0Q3VojwY", | ||||
|     grid: "8QqnMzx393bx", | ||||
|     calendar: "xWbu3jpNWapp", | ||||
|     table: "2FvYrpmOXm29", | ||||
|     geoMap: "81SGnPGMk7Xc", | ||||
|     board: "CtBQqbwXDx1w" | ||||
| }; | ||||
|  | ||||
| export function getHelpUrlForNote(note: FNote | null | undefined) { | ||||
|     if (note && note.type !== "book" && byNoteType[note.type]) { | ||||
|         return byNoteType[note.type]; | ||||
|     } else if (note?.hasLabel("calendarRoot")) { | ||||
|         return "l0tKav7yLHGF"; | ||||
|     } else if (note?.hasLabel("textSnippet")) { | ||||
|         return "pwc194wlRzcH"; | ||||
|     } else if (note && note.type === "book") { | ||||
|         return byBookType[note.getAttributeValue("label", "viewType") as ViewTypeOptions ?? ""] | ||||
|     } | ||||
| } | ||||
| @@ -1,8 +1,8 @@ | ||||
| import { t } from "i18next"; | ||||
| import "./FloatingButtons.css"; | ||||
| import Button from "./react/Button"; | ||||
| import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useNoteProperty, useTriliumEvent, useTriliumEvents, useTriliumOption, useTriliumOptionBool } from "./react/hooks"; | ||||
| import { useContext, useEffect, useMemo, useRef, useState } from "preact/hooks"; | ||||
| import { useNoteContext, useNoteProperty, useTriliumEvent, useTriliumEvents } from "./react/hooks"; | ||||
| import { useContext, useEffect, useMemo, useState } from "preact/hooks"; | ||||
| import { ParentComponent } from "./react/react_utils"; | ||||
| import attributes from "../services/attributes"; | ||||
| import { EventData, EventNames } from "../components/app_context"; | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import NoteContext from "../components/note_context"; | ||||
| import FNote from "../entities/fnote"; | ||||
| import ActionButton, { ActionButtonProps } from "./react/ActionButton"; | ||||
| import { useNoteLabelBoolean, useTriliumOption } from "./react/hooks"; | ||||
| import { useEffect, useRef, useState } from "preact/hooks"; | ||||
| import { useEffect, useMemo, useRef, useState } from "preact/hooks"; | ||||
| import { createImageSrcUrl, openInAppHelpFromUrl } from "../services/utils"; | ||||
| import server from "../services/server"; | ||||
| import { SaveSqlConsoleResponse } from "@triliumnext/commons"; | ||||
| @@ -15,6 +15,7 @@ import { copyImageReferenceToClipboard } from "../services/image"; | ||||
| import tree from "../services/tree"; | ||||
| import protected_session_holder from "../services/protected_session_holder"; | ||||
| import options from "../services/options"; | ||||
| import { getHelpUrlForNote } from "../services/in_app_help"; | ||||
|  | ||||
| export interface FloatingButtonDefinition { | ||||
|     component: (context: FloatingButtonContext) => VNode; | ||||
| @@ -104,6 +105,10 @@ export const FLOATING_BUTTON_DEFINITIONS: FloatingButtonDefinition[] = [ | ||||
|         isEnabled: ({ note, noteContext }) => | ||||
|             ["mermaid", "mindMap"].includes(note?.type ?? "") | ||||
|             && note?.isContentAvailable() && noteContext?.viewScope?.viewMode === "default" | ||||
|     }, | ||||
|     { | ||||
|         component: InAppHelpButton, | ||||
|         isEnabled: ({ note }) => !!getHelpUrlForNote(note) | ||||
|     } | ||||
| ]; | ||||
|  | ||||
| @@ -304,3 +309,15 @@ function ExportImageButtons({ triggerEvent }: FloatingButtonContext) { | ||||
|         </> | ||||
|     ) | ||||
| } | ||||
|  | ||||
| function InAppHelpButton({ note }: FloatingButtonContext) { | ||||
|     const helpUrl = getHelpUrlForNote(note); | ||||
|  | ||||
|     return ( | ||||
|         <FloatingButton | ||||
|             icon="bx bx-help-circle" | ||||
|             text={t("help-button.title")} | ||||
|             onClick={() => helpUrl && openInAppHelpFromUrl(helpUrl)} | ||||
|         /> | ||||
|     ) | ||||
| } | ||||
| @@ -1,78 +0,0 @@ | ||||
| import { type EventData } from "../../components/app_context.js"; | ||||
| import type FNote from "../../entities/fnote.js"; | ||||
| import type { NoteType } from "../../entities/fnote.js"; | ||||
| import { t } from "../../services/i18n.js"; | ||||
| import type { ViewTypeOptions } from "../../services/note_list_renderer.js"; | ||||
| import NoteContextAwareWidget from "../note_context_aware_widget.js"; | ||||
|  | ||||
| const TPL = /*html*/` | ||||
| <button class="open-contextual-help-button" title="${t("help-button.title")}"> | ||||
|     <span class="bx bx-help-circle"></span> | ||||
| </button> | ||||
| `; | ||||
|  | ||||
| export const byNoteType: Record<Exclude<NoteType, "book">, string | null> = { | ||||
|     canvas: null, | ||||
|     code: null, | ||||
|     contentWidget: null, | ||||
|     doc: null, | ||||
|     file: null, | ||||
|     image: null, | ||||
|     launcher: null, | ||||
|     mermaid: null, | ||||
|     mindMap: null, | ||||
|     noteMap: null, | ||||
|     relationMap: null, | ||||
|     render: null, | ||||
|     search: null, | ||||
|     text: null, | ||||
|     webView: null, | ||||
|     aiChat: null | ||||
| }; | ||||
|  | ||||
| export const byBookType: Record<ViewTypeOptions, string | null> = { | ||||
|     list: "mULW0Q3VojwY", | ||||
|     grid: "8QqnMzx393bx", | ||||
|     calendar: "xWbu3jpNWapp", | ||||
|     table: "2FvYrpmOXm29", | ||||
|     geoMap: "81SGnPGMk7Xc", | ||||
|     board: "CtBQqbwXDx1w" | ||||
| }; | ||||
|  | ||||
| export default class ContextualHelpButton extends NoteContextAwareWidget { | ||||
|  | ||||
|     isEnabled() { | ||||
|         if (!super.isEnabled()) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return !!ContextualHelpButton.#getUrlToOpen(this.note); | ||||
|     } | ||||
|  | ||||
|     doRender() { | ||||
|         this.$widget = $(TPL); | ||||
|     } | ||||
|  | ||||
|     static #getUrlToOpen(note: FNote | null | undefined) { | ||||
|         if (note && note.type !== "book" && byNoteType[note.type]) { | ||||
|             return byNoteType[note.type]; | ||||
|         } else if (note?.hasLabel("calendarRoot")) { | ||||
|             return "l0tKav7yLHGF"; | ||||
|         } else if (note?.hasLabel("textSnippet")) { | ||||
|             return "pwc194wlRzcH"; | ||||
|         } else if (note && note.type === "book") { | ||||
|             return byBookType[note.getAttributeValue("label", "viewType") as ViewTypeOptions ?? ""] | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async refreshWithNote(note: FNote | null | undefined): Promise<void> { | ||||
|         this.$widget.attr("data-in-app-help", ContextualHelpButton.#getUrlToOpen(this.note) ?? ""); | ||||
|     } | ||||
|  | ||||
|     entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) { | ||||
|         if (this.note?.type === "book" && loadResults.getAttributeRows().find((attr) => attr.noteId === this.noteId && attr.name === "viewType")) { | ||||
|             this.refresh(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user