client/refactor: de-duplicate the note type mapping

This commit is contained in:
Adorian Doran 2025-07-04 13:38:02 +03:00
parent f90e2fb484
commit 821e4b17cb
2 changed files with 82 additions and 87 deletions

View File

@ -1,43 +1,65 @@
import server from "./server.js";
import froca from "./froca.js";
import { t } from "./i18n.js"; import { t } from "./i18n.js";
import type { MenuItem, MenuItemBadge } from "../menus/context_menu.js"; import froca from "./froca.js";
import server from "./server.js";
import type { MenuCommandItem, MenuItem, MenuItemBadge } from "../menus/context_menu.js";
import type { NoteType } from "../entities/fnote.js";
import type { TreeCommandNames } from "../menus/tree_context_menu.js"; import type { TreeCommandNames } from "../menus/tree_context_menu.js";
export interface NoteTypeMapping {
type: NoteType;
mime?: string;
title: string;
icon?: string;
/** Indicates that this note type is part of a beta feature. */
isBeta?: boolean;
/** Indicates that this note type cannot be created by the user. */
reserved?: boolean;
/** Indicates that once a note of this type is created, its type can no longer be changed. */
static?: boolean;
}
export const NOTE_TYPES: NoteTypeMapping[] = [
// The suggested note type ordering method: insert the item into the corresponding group,
// then ensure the items within the group are ordered alphabetically.
// The default note type (always the first item)
{ type: "text", mime: "text/html", title: t("note_types.text"), icon: "bx-note" },
// Text notes group
{ type: "book", mime: "", title: t("note_types.book"), icon: "bx-book" },
// Graphic notes
{ type: "canvas", mime: "application/json", title: t("note_types.canvas"), icon: "bx-pen" },
{ type: "mermaid", mime: "text/mermaid", title: t("note_types.mermaid-diagram"), icon: "bx-selection" },
// Map notes
{ type: "geoMap", mime: "application/json", title: t("note_types.geo-map"), icon: "bx-map-alt", isBeta: true },
{ type: "mindMap", mime: "application/json", title: t("note_types.mind-map"), icon: "bx-sitemap" },
{ type: "noteMap", mime: "", title: t("note_types.note-map"), icon: "bxs-network-chart", static: true },
{ type: "relationMap", mime: "application/json", title: t("note_types.relation-map"), icon: "bxs-network-chart" },
// Misc note types
{ type: "render", mime: "", title: t("note_types.render-note"), icon: "bx-extension" },
{ type: "search", title: t("note_types.saved-search"), icon: "bx-file-find", static: true },
{ type: "webView", mime: "", title: t("note_types.web-view"), icon: "bx-globe-alt" },
// Code notes
{ type: "code", mime: "text/plain", title: t("note_types.code"), icon: "bx-code" },
// Reserved types (cannot be created by the user)
{ type: "contentWidget", mime: "", title: t("note_types.widget"), reserved: true },
{ type: "doc", mime: "", title: t("note_types.doc"), reserved: true },
{ type: "file", title: t("note_types.file"), reserved: true },
{ type: "image", title: t("note_types.image"), reserved: true },
{ type: "launcher", mime: "", title: t("note_types.launcher"), reserved: true },
{ type: "aiChat", mime: "application/json", title: t("note_types.ai-chat"), reserved: true }
];
const SEPARATOR = { title: "----" }; const SEPARATOR = { title: "----" };
const BETA_BADGE: MenuItemBadge = {title: t("note_types.beta-feature")};
async function getNoteTypeItems(command?: TreeCommandNames) { async function getNoteTypeItems(command?: TreeCommandNames) {
const items: MenuItem<TreeCommandNames>[] = [ const items: MenuItem<TreeCommandNames>[] = [
// The suggested note type ordering method: insert the item into the corresponding group, ...getBlankNoteTypes(command),
// then ensure the items within the group are ordered alphabetically.
// Please keep the order synced with the listing found also in aps/client/src/widgets/note_types.ts.
// The default note type (always the first item)
{ title: t("note_types.text"), command, type: "text", uiIcon: "bx bx-note" },
// Text notes group
{ title: t("note_types.book"), command, type: "book", uiIcon: "bx bx-book" },
// Graphic notes
{ title: t("note_types.canvas"), command, type: "canvas", uiIcon: "bx bx-pen" },
{ title: t("note_types.mermaid-diagram"), command, type: "mermaid", uiIcon: "bx bx-selection" },
// Map notes
{ title: t("note_types.geo-map"), command, type: "geoMap", uiIcon: "bx bx-map-alt" },
{ title: t("note_types.mind-map"), command, type: "mindMap", uiIcon: "bx bx-sitemap", badges: [BETA_BADGE]},
{ title: t("note_types.note-map"), command, type: "noteMap", uiIcon: "bx bxs-network-chart" },
{ title: t("note_types.relation-map"), command, type: "relationMap", uiIcon: "bx bxs-network-chart" },
// Misc note types
{ title: t("note_types.render-note"), command, type: "render", uiIcon: "bx bx-extension" },
{ title: t("note_types.saved-search"), command, type: "search", uiIcon: "bx bx-file-find" },
{ title: t("note_types.web-view"), command, type: "webView", uiIcon: "bx bx-globe-alt" },
// Code notes
{ title: t("note_types.code"), command, type: "code", uiIcon: "bx bx-code" },
// Templates
...await getBuiltInTemplates(command), ...await getBuiltInTemplates(command),
...await getUserTemplates(command) ...await getUserTemplates(command)
]; ];
@ -45,6 +67,24 @@ async function getNoteTypeItems(command?: TreeCommandNames) {
return items; return items;
} }
function getBlankNoteTypes(command): MenuItem<TreeCommandNames>[] {
return NOTE_TYPES.filter((nt) => !nt.reserved).map((nt) => {
const menuItem: MenuCommandItem<TreeCommandNames> = {
title: nt.title,
command,
type: nt.type,
uiIcon: "bx " + nt.icon,
badges: []
}
if (nt.isBeta) {
menuItem.badges?.push({title: t("note_types.beta-feature")});
}
return menuItem;
});
}
async function getUserTemplates(command?: TreeCommandNames) { async function getUserTemplates(command?: TreeCommandNames) {
const templateNoteIds = await server.get<string[]>("search-templates"); const templateNoteIds = await server.get<string[]>("search-templates");
const templateNotes = await froca.getNotes(templateNoteIds); const templateNotes = await froca.getNotes(templateNoteIds);

View File

@ -1,60 +1,15 @@
import server from "../services/server.js"; import { Dropdown } from "bootstrap";
import { NOTE_TYPES } from "../services/note_types.js";
import { t } from "../services/i18n.js";
import dialogService from "../services/dialog.js";
import mimeTypesService from "../services/mime_types.js"; import mimeTypesService from "../services/mime_types.js";
import NoteContextAwareWidget from "./note_context_aware_widget.js"; import NoteContextAwareWidget from "./note_context_aware_widget.js";
import dialogService from "../services/dialog.js"; import server from "../services/server.js";
import { t } from "../services/i18n.js";
import type FNote from "../entities/fnote.js";
import type { NoteType } from "../entities/fnote.js";
import type { EventData } from "../components/app_context.js"; import type { EventData } from "../components/app_context.js";
import { Dropdown } from "bootstrap"; import type { NoteType } from "../entities/fnote.js";
import type FNote from "../entities/fnote.js";
interface NoteTypeMapping { const NOT_SELECTABLE_NOTE_TYPES = NOTE_TYPES.filter((nt) => nt.reserved || nt.static).map((nt) => nt.type);
type: NoteType;
mime?: string;
title: string;
isBeta?: boolean;
selectable: boolean;
}
const NOTE_TYPES: NoteTypeMapping[] = [
// The suggested note type ordering method: insert the item into the corresponding group,
// then ensure the items within the group are ordered alphabetically.
// Please keep the order synced with the listing found also in apps/client/src/services/note_types.ts.
// The default note type (always the first item)
{ type: "text", mime: "text/html", title: t("note_types.text"), selectable: true },
// Text notes group
{ type: "book", mime: "", title: t("note_types.book"), selectable: true },
// Graphic notes
{ type: "canvas", mime: "application/json", title: t("note_types.canvas"), selectable: true },
{ type: "mermaid", mime: "text/mermaid", title: t("note_types.mermaid-diagram"), selectable: true },
// Map notes
{ type: "geoMap", mime: "application/json", title: t("note_types.geo-map"), isBeta: true, selectable: true },
{ type: "mindMap", mime: "application/json", title: t("note_types.mind-map"), selectable: true },
{ type: "relationMap", mime: "application/json", title: t("note_types.relation-map"), selectable: true },
// Misc note types
{ type: "render", mime: "", title: t("note_types.render-note"), selectable: true },
{ type: "webView", mime: "", title: t("note_types.web-view"), selectable: true },
// Code notes
{ type: "code", mime: "text/plain", title: t("note_types.code"), selectable: true },
// Reserved types (cannot be created by the user)
{ type: "contentWidget", mime: "", title: t("note_types.widget"), selectable: false },
{ type: "doc", mime: "", title: t("note_types.doc"), selectable: false },
{ type: "file", title: t("note_types.file"), selectable: false },
{ type: "image", title: t("note_types.image"), selectable: false },
{ type: "launcher", mime: "", title: t("note_types.launcher"), selectable: false },
{ type: "noteMap", mime: "", title: t("note_types.note-map"), selectable: false },
{ type: "search", title: t("note_types.saved-search"), selectable: false },
{ type: "aiChat", mime: "application/json", title: t("note_types.ai-chat"), selectable: false }
];
const NOT_SELECTABLE_NOTE_TYPES = NOTE_TYPES.filter((nt) => !nt.selectable).map((nt) => nt.type);
const TPL = /*html*/` const TPL = /*html*/`
<div class="dropdown note-type-widget"> <div class="dropdown note-type-widget">
@ -110,7 +65,7 @@ export default class NoteTypeWidget extends NoteContextAwareWidget {
return; return;
} }
for (const noteType of NOTE_TYPES.filter((nt) => nt.selectable)) { for (const noteType of NOTE_TYPES.filter((nt) => !nt.reserved && !nt.static)) {
let $typeLink: JQuery<HTMLElement>; let $typeLink: JQuery<HTMLElement>;
const $title = $("<span>").text(noteType.title); const $title = $("<span>").text(noteType.title);