mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	feat(react/dialogs): port include_note
This commit is contained in:
		| @@ -202,7 +202,7 @@ | ||||
|     "box_size_small": "小型 (显示大约10行)", | ||||
|     "box_size_medium": "中型 (显示大约30行)", | ||||
|     "box_size_full": "完整显示(完整文本框)", | ||||
|     "button_include": "包含笔记 <kbd>回车</kbd>" | ||||
|     "button_include": "包含笔记" | ||||
|   }, | ||||
|   "info": { | ||||
|     "modalTitle": "信息消息", | ||||
|   | ||||
| @@ -201,7 +201,7 @@ | ||||
|     "box_size_small": "klein (~ 10 Zeilen)", | ||||
|     "box_size_medium": "mittel (~ 30 Zeilen)", | ||||
|     "box_size_full": "vollständig (Feld zeigt vollständigen Text)", | ||||
|     "button_include": "Notiz beifügen <kbd>Eingabetaste</kbd>" | ||||
|     "button_include": "Notiz beifügen" | ||||
|   }, | ||||
|   "info": { | ||||
|     "modalTitle": "Infonachricht", | ||||
|   | ||||
| @@ -203,7 +203,7 @@ | ||||
|     "box_size_small": "small (~ 10 lines)", | ||||
|     "box_size_medium": "medium (~ 30 lines)", | ||||
|     "box_size_full": "full (box shows complete text)", | ||||
|     "button_include": "Include note <kbd>enter</kbd>" | ||||
|     "button_include": "Include note" | ||||
|   }, | ||||
|   "info": { | ||||
|     "modalTitle": "Info message", | ||||
|   | ||||
| @@ -202,7 +202,7 @@ | ||||
|     "box_size_small": "pequeño (~ 10 líneas)", | ||||
|     "box_size_medium": "medio (~ 30 líneas)", | ||||
|     "box_size_full": "completo (el cuadro muestra el texto completo)", | ||||
|     "button_include": "Incluir nota <kbd>Enter</kbd>" | ||||
|     "button_include": "Incluir nota" | ||||
|   }, | ||||
|   "info": { | ||||
|     "modalTitle": "Mensaje informativo", | ||||
|   | ||||
| @@ -201,7 +201,7 @@ | ||||
|     "box_size_small": "petit (~ 10 lignes)", | ||||
|     "box_size_medium": "moyen (~ 30 lignes)", | ||||
|     "box_size_full": "complet (la boîte affiche le texte complet)", | ||||
|     "button_include": "Inclure une note <kbd>Entrée</kbd>" | ||||
|     "button_include": "Inclure une note" | ||||
|   }, | ||||
|   "info": { | ||||
|     "modalTitle": "Message d'information", | ||||
|   | ||||
| @@ -750,7 +750,7 @@ | ||||
|     "box_size_medium": "mediu (~ 30 de rânduri)", | ||||
|     "box_size_prompt": "Dimensiunea căsuței notiței incluse:", | ||||
|     "box_size_small": "mică (~ 10 rânduri)", | ||||
|     "button_include": "Include notița <kbd>Enter</kbd>", | ||||
|     "button_include": "Include notița", | ||||
|     "dialog_title": "Includere notița", | ||||
|     "label_note": "Notiță", | ||||
|     "placeholder_search": "căutați notița după denumirea ei", | ||||
|   | ||||
| @@ -203,7 +203,7 @@ | ||||
|     "box_size_small": "mala (~ 10 redova)", | ||||
|     "box_size_medium": "srednja (~ 30 redova)", | ||||
|     "box_size_full": "puna (kutija prikazuje ceo tekst)", | ||||
|     "button_include": "Uključi belešku <kbd>enter</kbd>" | ||||
|     "button_include": "Uključi belešku" | ||||
|   }, | ||||
|   "info": { | ||||
|     "modalTitle": "Informativna poruka", | ||||
|   | ||||
| @@ -185,7 +185,7 @@ | ||||
|     "box_size_small": "小型 (顯示大約10行)", | ||||
|     "box_size_medium": "中型 (顯示大約30行)", | ||||
|     "box_size_full": "完整顯示(完整文字框)", | ||||
|     "button_include": "包含筆記 <kbd>Enter</kbd>" | ||||
|     "button_include": "包含筆記" | ||||
|   }, | ||||
|   "info": { | ||||
|     "modalTitle": "資訊消息", | ||||
|   | ||||
| @@ -1,116 +0,0 @@ | ||||
| import { t } from "../../services/i18n.js"; | ||||
| import treeService from "../../services/tree.js"; | ||||
| import noteAutocompleteService from "../../services/note_autocomplete.js"; | ||||
| import froca from "../../services/froca.js"; | ||||
| import BasicWidget from "../basic_widget.js"; | ||||
| import { Modal } from "bootstrap"; | ||||
| import type { EventData } from "../../components/app_context.js"; | ||||
| import type EditableTextTypeWidget from "../type_widgets/editable_text.js"; | ||||
| import { openDialog } from "../../services/dialog.js"; | ||||
|  | ||||
| const TPL = /*html*/` | ||||
| <div class="include-note-dialog modal mx-auto" tabindex="-1" role="dialog"> | ||||
|     <div class="modal-dialog modal-lg" role="document"> | ||||
|         <div class="modal-content"> | ||||
|             <div class="modal-header"> | ||||
|                 <h5 class="modal-title">${t("include_note.dialog_title")}</h5> | ||||
|                 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("include_note.close")}"></button> | ||||
|             </div> | ||||
|             <form class="include-note-form"> | ||||
|                 <div class="modal-body"> | ||||
|                     <div class="form-group"> | ||||
|                         <label for="include-note-autocomplete">${t("include_note.label_note")}</label> | ||||
|                         <div class="input-group"> | ||||
|                             <input class="include-note-autocomplete form-control" placeholder="${t("include_note.placeholder_search")}"> | ||||
|                         </div> | ||||
|                     </div> | ||||
|  | ||||
|                     ${t("include_note.box_size_prompt")} | ||||
|  | ||||
|                     <div class="form-check"> | ||||
|                         <label class="form-check-label tn-radio"> | ||||
|                             <input class="form-check-input" type="radio" name="include-note-box-size" value="small"> | ||||
|                             ${t("include_note.box_size_small")} | ||||
|                         </label> | ||||
|                     </div> | ||||
|                     <div class="form-check"> | ||||
|                         <label class="form-check-label tn-radio"> | ||||
|                             <input class="form-check-input" type="radio" name="include-note-box-size" value="medium" checked> | ||||
|                             ${t("include_note.box_size_medium")} | ||||
|                         </label> | ||||
|                     </div> | ||||
|                     <div class="form-check"> | ||||
|                         <label class="form-check-label tn-radio"> | ||||
|                             <input class="form-check-input" type="radio" name="include-note-box-size" value="full"> | ||||
|                             ${t("include_note.box_size_full")} | ||||
|                         </label> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <div class="modal-footer"> | ||||
|                     <button type="submit" class="btn btn-primary">${t("include_note.button_include")}</button> | ||||
|                 </div> | ||||
|             </form> | ||||
|         </div> | ||||
|     </div> | ||||
| </div>`; | ||||
|  | ||||
| export default class IncludeNoteDialog extends BasicWidget { | ||||
|  | ||||
|     private modal!: bootstrap.Modal; | ||||
|     private $form!: JQuery<HTMLElement>; | ||||
|     private $autoComplete!: JQuery<HTMLElement>; | ||||
|     private textTypeWidget?: EditableTextTypeWidget; | ||||
|  | ||||
|     doRender() { | ||||
|         this.$widget = $(TPL); | ||||
|         this.modal = Modal.getOrCreateInstance(this.$widget[0]); | ||||
|         this.$form = this.$widget.find(".include-note-form"); | ||||
|         this.$autoComplete = this.$widget.find(".include-note-autocomplete"); | ||||
|         this.$form.on("submit", () => { | ||||
|             const notePath = this.$autoComplete.getSelectedNotePath(); | ||||
|  | ||||
|             if (notePath) { | ||||
|                 this.modal.hide(); | ||||
|                 this.includeNote(notePath); | ||||
|             } else { | ||||
|                 logError("No noteId to include."); | ||||
|             } | ||||
|  | ||||
|             return false; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     async showIncludeNoteDialogEvent({ textTypeWidget }: EventData<"showIncludeDialog">) { | ||||
|         this.textTypeWidget = textTypeWidget; | ||||
|         await this.refresh(); | ||||
|         openDialog(this.$widget); | ||||
|  | ||||
|         this.$autoComplete.trigger("focus").trigger("select"); // to be able to quickly remove entered text | ||||
|     } | ||||
|  | ||||
|     async refresh() { | ||||
|         this.$autoComplete.val(""); | ||||
|         noteAutocompleteService.initNoteAutocomplete(this.$autoComplete, { | ||||
|             hideGoToSelectedNoteButton: true, | ||||
|             allowCreatingNotes: true | ||||
|         }); | ||||
|         noteAutocompleteService.showRecentNotes(this.$autoComplete); | ||||
|     } | ||||
|  | ||||
|     async includeNote(notePath: string) { | ||||
|         const noteId = treeService.getNoteIdFromUrl(notePath); | ||||
|         if (!noteId) { | ||||
|             return; | ||||
|         } | ||||
|         const note = await froca.getNote(noteId); | ||||
|         const boxSize = $("input[name='include-note-box-size']:checked").val() as string; | ||||
|  | ||||
|         if (["image", "canvas", "mermaid"].includes(note?.type ?? "")) { | ||||
|             // there's no benefit to use insert note functionlity for images, | ||||
|             // so we'll just add an IMG tag | ||||
|             this.textTypeWidget?.addImage(noteId); | ||||
|         } else { | ||||
|             this.textTypeWidget?.addIncludeNote(noteId, boxSize); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										99
									
								
								apps/client/src/widgets/dialogs/include_note.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								apps/client/src/widgets/dialogs/include_note.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| import { useRef, useState } from "preact/compat"; | ||||
| import type { EventData } from "../../components/app_context"; | ||||
| import { closeActiveDialog, openDialog } from "../../services/dialog"; | ||||
| import { t } from "../../services/i18n"; | ||||
| import FormGroup from "../react/FormGroup"; | ||||
| import FormRadioGroup from "../react/FormRadioGroup"; | ||||
| import Modal from "../react/Modal"; | ||||
| import NoteAutocomplete from "../react/NoteAutocomplete"; | ||||
| import ReactBasicWidget from "../react/ReactBasicWidget"; | ||||
| import Button from "../react/Button"; | ||||
| import note_autocomplete, { Suggestion } from "../../services/note_autocomplete"; | ||||
| import tree from "../../services/tree"; | ||||
| import froca from "../../services/froca"; | ||||
| import EditableTextTypeWidget from "../type_widgets/editable_text"; | ||||
|  | ||||
| interface IncludeNoteDialogProps { | ||||
|     textTypeWidget?: EditableTextTypeWidget; | ||||
| } | ||||
|  | ||||
| function IncludeNoteDialogComponent({ textTypeWidget }: IncludeNoteDialogProps) { | ||||
|     const [suggestion, setSuggestion] = useState<Suggestion | null>(null); | ||||
|     const [boxSize, setBoxSize] = useState("medium"); | ||||
|     const inputRef = useRef<HTMLInputElement>(null); | ||||
|  | ||||
|     return (textTypeWidget && | ||||
|         <Modal | ||||
|             className="include-note-dialog" | ||||
|             title={t("include_note.dialog_title")} | ||||
|             size="lg" | ||||
|             onShown={() => { | ||||
|                 inputRef.current?.focus(); | ||||
|                 note_autocomplete.showRecentNotes($(inputRef.current!)); | ||||
|             }} | ||||
|             onSubmit={() => { | ||||
|                 if (!suggestion?.notePath) { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 closeActiveDialog(); | ||||
|                 includeNote(suggestion.notePath, textTypeWidget); | ||||
|             }} | ||||
|             footer={ | ||||
|                 <Button text={t("include_note.button_include")} keyboardShortcut="Enter" /> | ||||
|             } | ||||
|         > | ||||
|             <FormGroup label={t("include_note.label_note")}> | ||||
|                 <NoteAutocomplete | ||||
|                     placeholder={t("include_note.placeholder_search")} | ||||
|                     onChange={setSuggestion} | ||||
|                     inputRef={inputRef} | ||||
|                 /> | ||||
|             </FormGroup> | ||||
|  | ||||
|             <FormGroup label={t("include_note.box_size_prompt")}> | ||||
|                 <FormRadioGroup name="include-note-box-size" | ||||
|                     currentValue={boxSize} onChange={setBoxSize} | ||||
|                     values={[ | ||||
|                         { label: t("include_note.box_size_small"), value: "small" }, | ||||
|                         { label: t("include_note.box_size_medium"), value: "medium" }, | ||||
|                         { label: t("include_note.box_size_full"), value: "full" }, | ||||
|                     ]} | ||||
|                 /> | ||||
|             </FormGroup> | ||||
|         </Modal> | ||||
|     ) | ||||
| } | ||||
|  | ||||
| export default class IncludeNoteDialog extends ReactBasicWidget { | ||||
|  | ||||
|     private props: IncludeNoteDialogProps = {}; | ||||
|  | ||||
|     get component() { | ||||
|         return <IncludeNoteDialogComponent {...this.props} />; | ||||
|     } | ||||
|  | ||||
|     async showIncludeNoteDialogEvent({ textTypeWidget }: EventData<"showIncludeDialog">) { | ||||
|         this.props = { textTypeWidget }; | ||||
|         this.doRender(); | ||||
|         openDialog(this.$widget); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| async function includeNote(notePath: string, textTypeWidget: EditableTextTypeWidget) { | ||||
|     const noteId = tree.getNoteIdFromUrl(notePath); | ||||
|     if (!noteId) { | ||||
|         return; | ||||
|     } | ||||
|     const note = await froca.getNote(noteId); | ||||
|     const boxSize = $("input[name='include-note-box-size']:checked").val() as string; | ||||
|  | ||||
|     if (["image", "canvas", "mermaid"].includes(note?.type ?? "")) { | ||||
|         // there's no benefit to use insert note functionlity for images, | ||||
|         // so we'll just add an IMG tag | ||||
|         textTypeWidget.addImage(noteId); | ||||
|     } else { | ||||
|         textTypeWidget.addIncludeNote(noteId, boxSize); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user