mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	chore(react/ribbon): change note type
This commit is contained in:
		| @@ -11,14 +11,6 @@ import type FNote from "../entities/fnote.js"; | |||||||
|  |  | ||||||
| const NOT_SELECTABLE_NOTE_TYPES = NOTE_TYPES.filter((nt) => nt.reserved || nt.static).map((nt) => nt.type); | const NOT_SELECTABLE_NOTE_TYPES = NOTE_TYPES.filter((nt) => nt.reserved || nt.static).map((nt) => nt.type); | ||||||
|  |  | ||||||
| const TPL = /*html*/` |  | ||||||
| <div class="dropdown note-type-widget"> |  | ||||||
|     <button type="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="btn btn-sm dropdown-toggle select-button note-type-button"> |  | ||||||
|         <span class=""></span> |  | ||||||
|     </button> |  | ||||||
| </div> |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| export default class NoteTypeWidget extends NoteContextAwareWidget { | export default class NoteTypeWidget extends NoteContextAwareWidget { | ||||||
|  |  | ||||||
|     private dropdown!: Dropdown; |     private dropdown!: Dropdown; | ||||||
| @@ -47,93 +39,4 @@ export default class NoteTypeWidget extends NoteContextAwareWidget { | |||||||
|         this.dropdown.hide(); |         this.dropdown.hide(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** the actual body is rendered lazily on note-type button click */ |  | ||||||
|     async renderDropdown() { |  | ||||||
|         this.$noteTypeDropdown.empty(); |  | ||||||
|  |  | ||||||
|         if (!this.note) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         for (const noteType of ) { |  | ||||||
|             let $typeLink: JQuery<HTMLElement>; |  | ||||||
|  |  | ||||||
|             if (noteType.type !== "code") { |  | ||||||
|                 $typeLink = $('<a class="dropdown-item">') |  | ||||||
|                     .attr("data-note-type", noteType.type) |  | ||||||
|                     .append('<span class="check">✓</span> ') |  | ||||||
|                     .append($title) |  | ||||||
|                     .on("click", (e) => { |  | ||||||
|                         const type = $typeLink.attr("data-note-type"); |  | ||||||
|                         const noteType = NOTE_TYPES.find((nt) => nt.type === type); |  | ||||||
|  |  | ||||||
|                         if (noteType) { |  | ||||||
|                             this.save(noteType.type, noteType.mime); |  | ||||||
|                         } |  | ||||||
|                     }); |  | ||||||
|             } else { |  | ||||||
|                 this.$noteTypeDropdown.append('<div class="dropdown-divider"></div>'); |  | ||||||
|                 $typeLink = $('<a class="dropdown-item disabled">').attr("data-note-type", noteType.type).append('<span class="check">✓</span> ').append($("<strong>").text()); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (this.note.type === noteType.type) { |  | ||||||
|                 $typeLink.addClass("selected"); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             this.$noteTypeDropdown.append($typeLink); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         for (const mimeType of ) { |  | ||||||
|             const $mimeLink = $('<a class="dropdown-item">') |  | ||||||
|                 .attr("data-mime-type", mimeType.mime) |  | ||||||
|                 .append('<span class="check">✓</span> ') |  | ||||||
|                 .on("click", (e) => { |  | ||||||
|                     const $link = $(e.target).closest(".dropdown-item"); |  | ||||||
|  |  | ||||||
|                     this.save("code", $link.attr("data-mime-type") ?? ""); |  | ||||||
|                 }); |  | ||||||
|  |  | ||||||
|             if (this.note.type === "code" && this.note.mime === mimeType.mime) { |  | ||||||
|                 $mimeLink.addClass("selected"); |  | ||||||
|  |  | ||||||
|                 this.$noteTypeDesc.text(mimeType.title); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             this.$noteTypeDropdown.append($mimeLink); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     async save(type: NoteType, mime?: string) { |  | ||||||
|         if (type === this.note?.type && mime === this.note?.mime) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (type !== this.note?.type && !(await this.confirmChangeIfContent())) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         await server.put(`notes/${this.noteId}/type`, { type, mime }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async confirmChangeIfContent() { |  | ||||||
|         if (!this.note) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         const blob = await this.note.getBlob(); |  | ||||||
|  |  | ||||||
|         if (!blob?.content || !blob.content.trim().length) { |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return await dialogService.confirm(t("note_types.confirm-change")); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) { |  | ||||||
|         if (loadResults.isNoteReloaded(this.noteId)) { |  | ||||||
|             this.refresh(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -76,14 +76,21 @@ interface FormListItemOpts { | |||||||
|     active?: boolean; |     active?: boolean; | ||||||
|     badges?: FormListBadge[]; |     badges?: FormListBadge[]; | ||||||
|     disabled?: boolean; |     disabled?: boolean; | ||||||
|  |     checked?: boolean; | ||||||
|  |     onClick?: () => void; | ||||||
| } | } | ||||||
|  |  | ||||||
| export function FormListItem({ children, icon, value, title, active, badges, disabled }: FormListItemOpts) { | export function FormListItem({ children, icon, value, title, active, badges, disabled, checked, onClick }: FormListItemOpts) { | ||||||
|  |     if (checked) { | ||||||
|  |         icon = "bx bx-check"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return ( |     return ( | ||||||
|         <a |         <a | ||||||
|             class={`dropdown-item ${active ? "active" : ""} ${disabled ? "disabled" : ""}`} |             class={`dropdown-item ${active ? "active" : ""} ${disabled ? "disabled" : ""}`} | ||||||
|             data-value={value} title={title} |             data-value={value} title={title} | ||||||
|             tabIndex={0} |             tabIndex={0} | ||||||
|  |             onClick={onClick} | ||||||
|         > |         > | ||||||
|             <Icon icon={icon} />  |             <Icon icon={icon} />  | ||||||
|             {children} |             {children} | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| import { useMemo } from "preact/hooks"; | import { useCallback, useMemo } from "preact/hooks"; | ||||||
| import Dropdown from "../react/Dropdown"; | import Dropdown from "../react/Dropdown"; | ||||||
| import { NOTE_TYPES } from "../../services/note_types"; | import { NOTE_TYPES } from "../../services/note_types"; | ||||||
| import { FormDivider, FormListBadge, FormListItem } from "../react/FormList"; | import { FormDivider, FormListBadge, FormListItem } from "../react/FormList"; | ||||||
| @@ -6,6 +6,8 @@ import { t } from "../../services/i18n"; | |||||||
| import { useNoteContext, useNoteProperty, useTriliumOption } from "../react/hooks"; | import { useNoteContext, useNoteProperty, useTriliumOption } from "../react/hooks"; | ||||||
| import mime_types from "../../services/mime_types"; | import mime_types from "../../services/mime_types"; | ||||||
| import { NoteType } from "@triliumnext/commons"; | import { NoteType } from "@triliumnext/commons"; | ||||||
|  | import server from "../../services/server"; | ||||||
|  | import dialog from "../../services/dialog"; | ||||||
|  |  | ||||||
| export default function BasicPropertiesTab() { | export default function BasicPropertiesTab() { | ||||||
|     return ( |     return ( | ||||||
| @@ -21,53 +23,79 @@ function NoteTypeWidget() { | |||||||
|     const mimeTypes = useMemo(() => mime_types.getMimeTypes().filter(mimeType => mimeType.enabled), [ codeNotesMimeTypes ]); |     const mimeTypes = useMemo(() => mime_types.getMimeTypes().filter(mimeType => mimeType.enabled), [ codeNotesMimeTypes ]); | ||||||
|      |      | ||||||
|     const { note } = useNoteContext(); |     const { note } = useNoteContext(); | ||||||
|     const type = useNoteProperty(note, "type") ?? undefined; |     const currentNoteType = useNoteProperty(note, "type") ?? undefined; | ||||||
|     const mime = useNoteProperty(note, "mime"); |     const currentNoteMime = useNoteProperty(note, "mime"); | ||||||
|  |  | ||||||
|  |     const changeNoteType = useCallback(async (type: NoteType, mime?: string) => { | ||||||
|  |         if (!note || (type === currentNoteType && mime === currentNoteMime)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Confirm change if the note already has a content. | ||||||
|  |         if (type !== currentNoteType) { | ||||||
|  |             const blob = await note.getBlob(); | ||||||
|  |  | ||||||
|  |             if (blob?.content && blob.content.trim().length && | ||||||
|  |                 !await (dialog.confirm(t("note_types.confirm-change")))) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         await server.put(`notes/${note.noteId}/type`, { type, mime }); | ||||||
|  |     }, [ note, currentNoteType, currentNoteMime ]); | ||||||
|  |  | ||||||
|     return ( |     return ( | ||||||
|         <> |         <div className="note-type-container"> | ||||||
|             <span>{t("basic_properties.note_type")}:</span>   |             <span>{t("basic_properties.note_type")}:</span>   | ||||||
|             <Dropdown |             <Dropdown | ||||||
|                 dropdownContainerClassName="note-type-dropdown" |                 dropdownContainerClassName="note-type-dropdown" | ||||||
|                 text={<span className="note-type-desc">{findTypeTitle(type, mime)}</span>} |                 text={<span className="note-type-desc">{findTypeTitle(currentNoteType, currentNoteMime)}</span>} | ||||||
|             > |             > | ||||||
|                 {noteTypes.map(noteType => { |                 {noteTypes.map(({ isNew, isBeta, type, mime, title }) => { | ||||||
|                     const badges: FormListBadge[] = []; |                     const badges: FormListBadge[] = []; | ||||||
|                     if (noteType.isNew) { |                     if (isNew) { | ||||||
|                         badges.push({ |                         badges.push({ | ||||||
|                             className: "new-note-type-badge", |                             className: "new-note-type-badge", | ||||||
|                             text: t("note_types.new-feature") |                             text: t("note_types.new-feature") | ||||||
|                         }); |                         }); | ||||||
|                     } |                     } | ||||||
|                     if (noteType.isBeta) { |                     if (isBeta) { | ||||||
|                         badges.push({ |                         badges.push({ | ||||||
|                             text: t("note_types.beta-feature") |                             text: t("note_types.beta-feature") | ||||||
|                         }); |                         }); | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     if (noteType.type !== "code") { |                     const checked = (type === currentNoteType); | ||||||
|  |                     if (type !== "code") { | ||||||
|                         return ( |                         return ( | ||||||
|                             <FormListItem |                             <FormListItem | ||||||
|  |                                 checked={checked} | ||||||
|                                 badges={badges} |                                 badges={badges} | ||||||
|                             >{noteType.title}</FormListItem>     |                                 onClick={() => changeNoteType(type, mime)} | ||||||
|  |                             >{title}</FormListItem>     | ||||||
|                         ); |                         ); | ||||||
|                     } else { |                     } else { | ||||||
|                         return ( |                         return ( | ||||||
|                             <> |                             <> | ||||||
|                                 <FormDivider /> |                                 <FormDivider /> | ||||||
|                                 <FormListItem disabled> |                                 <FormListItem | ||||||
|                                     <strong>{noteType.title}</strong> |                                     checked={checked} | ||||||
|  |                                     disabled                                     | ||||||
|  |                                 > | ||||||
|  |                                     <strong>{title}</strong> | ||||||
|                                 </FormListItem> |                                 </FormListItem> | ||||||
|                             </> |                             </> | ||||||
|                         ) |                         ) | ||||||
|                     } |                     } | ||||||
|                 })} |                 })} | ||||||
|  |  | ||||||
|                 {mimeTypes.map(mimeType => ( |                 {mimeTypes.map(({ title, mime }) => ( | ||||||
|                     <FormListItem>{mimeType.title}</FormListItem> |                     <FormListItem onClick={() => changeNoteType("code", mime)}> | ||||||
|  |                         {title} | ||||||
|  |                     </FormListItem> | ||||||
|                 ))} |                 ))} | ||||||
|             </Dropdown> |             </Dropdown> | ||||||
|         </> |         </div> | ||||||
|     )    |     )    | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,10 +10,6 @@ import type FNote from "../../entities/fnote.js"; | |||||||
| import NoteLanguageWidget from "../note_language.js"; | import NoteLanguageWidget from "../note_language.js"; | ||||||
|  |  | ||||||
| const TPL = /*html*/` | const TPL = /*html*/` | ||||||
|     <div class="note-type-container"> |  | ||||||
|  |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div class="protected-note-switch-container"></div> |     <div class="protected-note-switch-container"></div> | ||||||
|  |  | ||||||
|     <div class="editability-select-container"> |     <div class="editability-select-container"> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user